通知设置 新通知
编译php的imagick模块报错
空心菜 回复了问题 2 人关注 1 个回复 4753 次浏览 2017-09-24 12:04
Go Web框架gin vs echo
koyo 发表了文章 0 个评论 8072 次浏览 2017-09-10 20:36
Web框架类型
web框架的主流,是采用轻量级的中间件式框架,把网站变成只有api的一个个小服务,其他都扔到cdn之类的地方处理。
这种方式,开发快速、拼装能力强,要什么就加什么,不要的就不加,就像是乐高玩具,大受欢迎。
问题在于,这种框架有一堆,到底该选哪个。
Gin vs Echo
在golang中,这种杰出代表,有2个:gin 和 echo。
这两个框架,在同类中,路由性能最高,超出其他框架一大截。google了一大堆英文站,也没有找到这两个框架的比较。于是,在我们实际使用后,提供个比较。
先说结论:
- 如果你代表企业,最好选择gin,无痛开发。
- 如果是个人,开发个轻量服务,哪怕echo有点小问题,你也觉得没啥,那么,就用echo。
gin完胜框架成熟度
- gin拥有详尽的出错信息,极为方便调试。
- 这非常关键。团队项目,这个更加重要。
- echo在这方面,就略微逊色。使用框架的第一天,就遇到了明明路由语法写错了,却不报错、不给结果,也没有任何提示的情况。
gin微弱小胜路由性能
- gin的卖点,是所有web框架中,路由性能最好。
- echo的卖点,是它的路由性能,比gin还好10%。
一回事,都有点小不便:路由便利、灵活性
- 两个路由采用同一种算法,这种算法性能很高,但有个缺点: 不支持路由排序,会认为是路由冲突。
- 比如: 路由Get("/name")和 Get("/:id") ,一般来说,只要把Get("/name")放在Get("/:id")前面,就是不冲突的。路由模块,会先尝试匹配前面那个,没匹配上,再去匹配后面的。
- 而 gin和echo用的路由模块,会认为这两个路由是冲突的。gin会给出提醒,不让编译通过;echo完全不提醒,冲突就冲突了。。。
两个都不够好。框架的可持续发展
- gin的主创是2个大学生。每年寒暑假就频繁更新,快到期末考试了,就完全不更新了。两人不在的时候,有网友在帮忙热情的维护,但主要是修bug、整理中间件。框架本身的发展,还是靠主创寒暑假爆发。就是这样的框架,连csico都在用。。。
- 好在,gin的代码注释量大,易读性高,便于其他人参与。而且包装中间件,也超级容易。
- 作者本人的态度是,对于一个在github上,start达到5000+的项目,他怎么可能会不去维护。请大家放心使用,到寒暑假了,他自然会去更新。。。
- echo则是主创当前处于活跃状态,并且乐呵呵的想要开发2.0版。由于主创活跃,它自带了一些流行功能,比如websocket, http2, jwt授权。用gin的话,这些功能要自己包装个中间件,虽然也很容易就是了。
- 但echo的问题在于,它的代码毫无注释。作者现在是在劲头上,等3-6个月,在路上看到个穿超短的妹子,热情转移了,很快就会忘记当时代码是怎么写的。没有注释,不但别人不方便接手,自己也懒得再去看,于是慢慢就永不再更新。
- 缺少注释的开源包,大部分都有这个问题。echo最终会不会变成这个结局,我们无从得知。
综上总结
- echo的状态是当下主创本人活跃,框架还不太成熟,适合最轻量级服务;
- gin则是整体成熟、易于调试,但可以预期,框架本身发展不会太快,除非主创大学毕业,从事和golang相关的工作。
- echo的使用方式、命名,都参考了gin,两者很接近,切换框架很容易,所以不用担心选错。
更新
由于echo的路由冲突频繁且没有调试信息,目前不是合理选择。等作者补上了路由冲突检测,那么就还不错。
如果想要回避这种框架的路由冲突,又想享受类似的优秀,neo框架目前最接近.
原文地址:https://www.golangtc.com/t/56a38761b09ecc083100010c
使用phpize安装redis扩展报错
Something 回复了问题 2 人关注 1 个回复 4925 次浏览 2017-08-22 19:01
安装PHP编译出错合集记录
push 发表了文章 0 个评论 3485 次浏览 2017-06-15 19:08
-liconv -o sapi/fpm/php-fpm
/usr/bin/ld: cannot find -liconv
collect2: ld returned 1 exit status
make: *** [sapi/fpm/php-fpm] Error 1
初步定位是iconv的问题,解决方法 把libiconv卸载掉,进入libiconv源码目录执行:
# make uninstall再进入php源码目录:
# make clean
# ./configure –prefix=/usr/local/libiconv
# make
# make install
./configure php 时加上参数 --with-iconv=/usr/local/libiconv
情况二:
/usr/bin/ld: cannot find -lltdl
collect2: ld returned 1 exit status
make: *** [sapi/cgi/php-cgi] Error 1
解决办法安装包如下:
# yum install libtool-ltdl.x86_64 libtool-ltdl-devel.x86_64
情况三:
collect2: ld returned 1 exit status
make: *** [sapi/cgi/php-cgi] Error 1
解决办法, 请安装lib所需的安装包:
yum install ntp vim-enhanced gcc gcc-c++ gcc-g77 flex bison autoconf automake bzip2-devel ncurses-devel zlib-devel libjpeg-devel libpng-devel libtiff-devel freetype-devel libXpm-devel gettext-devel pam-devel kernel执行安装完以后即可解决问题
make && make install
情况四:
ext/iconv/iconv.o: In function `php_iconv_stream_filter_ctor’:编译参数如下:
/usr/local/soft/php-5.2.14/ext/iconv/iconv.c:2491: undefined reference to `libiconv_open’
collect2: ld returned 1 exit status
make: *** [sapi/cgi/php-cgi] Error 1
./configure –prefix=/usr/local/php –with-gd=/usr/local/gd –with-jpeg-dir=/usr/local/jpeg –with-png-dir=/usr/local/png –with-freetype-dir=/usr/local/freetype –with-mysql=/usr/local/mysql –enable-fastcgi –enable-fpm解决办法:
增加 --disable-cli 编译参数。
情况五:
ext/xmlreader/php_xmlreader.o: In function `zim_xmlreader_XML':
/usr/local/src/php-5.2.8/ext/xmlreader/php_xmlreader.c:1109: undefined reference to `xmlTextReaderSetup'
collect2: ld returned 1 exit status
make: *** [sapi/cgi/php-cgi] Error 1
解决办法:折腾了半天,最后先make clean 一下,然后把所有libxml2相关的包都装上重新编译就ok了。
情况六:
运行可能报错 :我遇到xsl和mcrypt两个库报错,重新安装一下xsl的dev包就可以:
CentOS : yum install libxslt-devel libmcrypt-devel如果你有其他的库不满足,搜索一下该库,安装一下即可,这一步应该没有太多问题。
Debian : apt-get install libxslt1-dev libmcrypt-dev
编译:make
我在Debian下make正常,但在CentOS下却提示make错误,
make: *** [sapi/fpm/php-fpm] Error 1 错误中出现 libiconv,应该是iconv包问题,
使用下面的命令替换即可:
make ZEND_EXTRA_LIBS='-liconv'
完成后:
make test
make install
Python操作各种数据库
空心菜 发表了文章 1 个评论 3237 次浏览 2017-04-27 17:54
一、操作mysql
python3中操作mysql数据需要安装一个第三方模块,pymysql,使用pip install pymysql安装即可,在python2中是MySQLdb模块,在python3中没有MySQLdb模块了,所以使用pymysql。
import pymysql上面的操作,获取到的返回结果都是元组,如果想获取到的结果是一个字典类型的话,可以使用下面这样的操作
# 创建连接,指定数据库的ip地址,账号、密码、端口号、要操作的数据库、字符集
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='data',charset='utf8')
# 创建游标
cursor = conn.cursor()
# 执行SQL,并返回收影响行数
effect_row = cursor.execute("update students set name = 'niuhy' where id = 1;")
# 执行SQL,并返回受影响行数
#effect_row = cursor.execute("update students set name = 'niuhy' where id = %s;", (1,))
# 执行SQL,并返回受影响行数
effect_row = cursor.executemany("insert into students (name,age) values (%s,%s); ", [("hangyang",18),("12345",20)])
#执行select语句
cursor.execute("select * from students;")
#获取查询结果的第一条数据,返回的是一个元组
row_1 = cursor.fetchone()
# 获取前n行数据
row_2 = cursor.fetchmany(3)
# 获取所有数据
row_3 = cursor.fetchall()
# 提交,不然无法保存新建或者修改的数据
conn.commit()
# 获取最新自增ID
new_id = cursor.lastrowid
print(new_id)
# 关闭游标
cursor.close()
# 关闭连接
conn.close()
import pymysql
# 创建连接,指定数据库的ip地址,账号、密码、端口号、要操作的数据库、字符集
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='data',charset='utf8')
# 创建游标
cursor = conn.cursor()
cursor = coon.cursor(cursor=pymysql.cursors.DictCursor)#需要指定游标的类型,字典类型
# 执行SQL
cursor.execute("select * from user;")
#获取返回结果,这个时候返回结果是一个字典
res = cursor.fetchone()#返回一条数据,如果结果是多条的话
print(res)
res2 = cursor.fetchall()#所有的数据一起返回
二、操作redis
redis是一个nosql类型的数据库,数据都存在内存中,有很快的读写速度,python操作redis使用redis模块,pip安装即可
import redis
r = redis.Redis(host='127.0.0.1',port=6379,db=0)#指定连接redis的端口和ip以及哪个数据库
r.set('name', 'value')#set string类型的值
r.setnx('name2', 'value')#设置的name的值,如果name不存在的时候才会设置
r.setex('name3', 'value', 3)#设置的name的值,和超时时间,过了时间key就会自动失效
r.mset(k1='v1',k2='v2')#批量设置值
r.get('name')#获取值
print(r.mget('k1','k2'))#批量获取key
r.delete('name')#删除值
r.delete('k1','k2')#批量删除
#======下面是操作哈希类型的
r.hset('hname', 'key', 'value')#set 哈希类型的值
r.hset('hname', 'key1', 'value2')#set 哈希类型的值
r.hsetnx('hname','key2','value23')#给name为hname设置key和value,和上面的不同的是key不存在的时候
#才会set
r.hmset('hname',{'k1':'v1','k2':'v2'})#批量设置哈希类型的key和value
r.hget('name', 'key')#获取哈希类型的值
print(r.hgetall('hname'))#获取这个name里所有的key和value
r.hdel('hname','key')#删除哈希类型的name里面指定的值
print(r.keys())#获取所有的key
三、操作mongodb
mongodb和redis一样,也是一个nosql类型的数据库,它和redis的区别是,redis把整个数据都放在内存,而mongodb是把数据放在磁盘上的。 python操作mongodb使用pymongo模块,pip安装即可,操作如下:
import pymongo分享转载原文:牛牛杂货铺。
conn = pymongo.MongoClient(host='211.149.218.16',port=27017)#连接mongodb
db = conn.szz#选择哪个数据库
db.authenticate('admin','123456')#如果有账号密码的话,指定账号密码
collection = db.stus#使用数据库里面哪个集合,就相当于mysql里面的表
collection.drop()#删除指定的集合,也就是删除这个表
stu={
'name':'牛牛',
'age':38,
'sex':'男'
}
stus = [
{'name':'python',
'addr':'北京',
'sex':'未知',
'age':38
},
{
'name':'mongodb',
'addr':'USA',
'money':18.01,
'age':20
}
]
collection.save(stu)#插入单条数据
collection.insert(stus)#插入单条和多条,如果是多条的话,传入的就是一个list
=====比较操作符=======
# $lt
# 小于
# $lte
# 小于等于
# $gt
# 大于
# $gte
# 大于等于
# $ne
# 不等于
$set 获取前面的结果集
collection.update({'name':'牛牛'},{'name':'niuhy','age':20})#更新数据
collection.update({'name':'牛牛'},{'$set':{'addr':'河南'}})#在原来数据的基础上修改
collection.update({'name':'牛牛'},
{'$set':{'addr':'河南'}},
multi=True)#multi参数的作用是如果有多个结果的话,是否全部修改
collection.remove({'name':'牛牛'})#删除指定的数据,如果不传入参数,删除的是全部的数据
collection.remove()#删除全部数据
data = collection.find({'name':'mongodb'})#查询指定的数据
all_data = collection.find()#不写参数就是查询所有的数据
my_data = collection.find({'age':{'$gte':18}})#查询大于18岁的
for d in my_data:#获取数据,所有查询数据都需要使用循环来获取
print(d)#每个元素都是一个字典
安装php54w-mcrypt报错
koyo 回复了问题 3 人关注 3 个回复 5496 次浏览 2017-04-10 13:56
Python字符串反转方法小记
空心菜 发表了文章 1 个评论 3186 次浏览 2017-04-09 15:29
No.1 切片方式
字符串的切片跟列表是一样的,主要是利用切片的扩展语法-1来实现
def rev1(cont):切片详细语法查看:https://docs.python.org/2/whatsnew/2.3.html#extended-slices
return cont[::-1]
No.2 列表reverse实现
利用列表的reverse()方法这个特性,可以先将字符串转换成列表,利用reverse()方法进行反转后,再处理成字符串。
def rev2(cont):
result = list(cont)
result.reverse()
return ''.join(result)
No.3 内置函数reversed实现
def rev3(cont):
return ''.join(reversed(cont))
No.4 递归方法
def rev4(cont):
if cont == "":
return cont
else:
return rev4(cont[1:])+cont[0]
# 在Python 3里,reduce()内置函数已经被从全局名字空间里移除了,它现在被放置在fucntools模块里
from functools import reduce
def rev5(cont):
return reduce(lambda x, y : y + x, cont)
No.5 字符串拼接
def rev6(cont):
new_string = ''
index = len(cont)
while index:
index -= 1 # index = index - 1
new_string += cont[index] # new_string = new_string + character
return new_string
def rev7(cont):
new_strings =
index = len(cont)
while index:
index -= 1
new_strings.append(cont[index])
return ''.join(new_strings)
如上几种方法效率比较:
#!/usr/bin/env python3时间结果如下:
# Author: nock
from functools import reduce
import timeit
cont = 'kcon' * 20
def rev1(cont):
return cont[::-1]
def rev2(cont):
result = list(cont)
result.reverse()
return ''.join(result)
def rev3(cont):
return ''.join(reversed(cont))
def rev4(cont):
if cont == "":
return cont
else:
return rev4(cont[1:])+cont[0]
def rev5(cont):
return reduce(lambda x, y : y + x, cont)
def rev6(cont):
new_string = ''
index = len(cont)
while index:
index -= 1 # index = index - 1
new_string += cont[index] # new_string = new_string + character
return new_string
def rev7(cont):
new_strings =
index = len(cont)
while index:
index -= 1
new_strings.append(cont[index])
return ''.join(new_strings)
if __name__ == '__main__':
print("rev1 run time is: %s" % min(timeit.repeat(lambda: rev1(cont))))
print("rev2 run time is: %s" % min(timeit.repeat(lambda: rev2(cont))))
print("rev3 run time is: %s" % min(timeit.repeat(lambda: rev3(cont))))
print("rev4 run time is: %s" % min(timeit.repeat(lambda: rev4(cont))))
print("rev5 run time is: %s" % min(timeit.repeat(lambda: rev5(cont))))
print("rev6 run time is: %s" % min(timeit.repeat(lambda: rev6(cont))))
print("rev7 run time is: %s" % min(timeit.repeat(lambda: rev7(cont))))
rev1 run time is: 0.45436444599181414所以如上可以看出,还是用切片的方法最好,所以记住切片步长为-1就可反转就好。
rev2 run time is: 2.3974227079888806
rev3 run time is: 2.633627591014374
rev4 run time is: 3.0160443240310997
rev5 run time is: 16.342944753996562
rev6 run time is: 12.666344199969899
rev7 run time is: 14.762871471000835
Python生成器解析式和Zip函数介绍
空心菜 发表了文章 0 个评论 3226 次浏览 2017-03-23 17:31
生成器解析式
对列表解析来说,只需要简单的把中括号换成小括号就可以了,生成器解析式是按需计算的或者说延迟计算的或者叫惰性求值。
#!/usr/bin/env python3
# Author: nock
def inc(x):
print('inc {0}'.format(x))
return x + 1
# 生成一个迭代器对象
obj = (inc(x) for x in range(10))
print(obj)
Result:
at 0x107d87678>
#!/usr/bin/env python3Result:
# Author: nock
# 生成一个迭代器对象
obj = (x for x in range(10))
l = [x for x in range(10)]
print(next(obj))
print(next(obj))
print(next(obj))
print(l[4])
try:
print(obj[1])
except Exception as e:
print("Exception is: {0}".format(e))
print(next(obj))
0生成器无下标获取。
1
2
4
Exception is: 'generator' object is not subscriptable
3
Zip
zip 函数用于合并多个可迭代对象,合并后的长度等于最短的可迭代对象的长度
解锁Python集合推导式和字典推导式
空心菜 发表了文章 0 个评论 3678 次浏览 2017-03-19 22:23
集合推导式
集合推导式(set comprehensions)跟列表推导式也是类似的, 唯一的区别在于它们使用大括号{}表示。
Code:
sets = {x for x in range(10)}
Result:
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
集合解析把列表解析中的中括号变成大括号,返回集合。
下面我们来个应用场景,一直一个列表中有很多元素,我们做到快速去重。
Code:集合推导式生成内容,结果要是可hash的:
heavy = {x for x in [2, 3, 5, 3, 5, 2, 6]}
print(heavy)
Result:
{2, 3, 5, 6}
字典推导式
字典推导式(dict comprehensions)和列表推导的使用方法也是类似的。
字典解析也是使用大括号包围,并且需要两个表达式,一个生成key, 一个生成value 两个表达式之间使用冒号分割,返回结果是字典.
说了这么多推导式,为什么没有元组推导式呢,元组和列表的操作几乎是一样的,除了不可变特性以外
Code:
tuple([x for x in range(10)])
Result:
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
Python使用类来写装饰器
空心菜 发表了文章 0 个评论 2438 次浏览 2017-03-19 17:37
示例代码如下:
class Foo:运行结果:
def __call__(self, *args, **kwargs):
print('call....')
def test(self):#
print('test....')
if __name__ == '__main__':
t = Foo()#实例化类
t.test()#正常调用实例方法
t()#直接调用实例化之后的对象
>>>test.... #这个是调用test方法的时候输出的理解了上面的之后,就可以使用class来写一个装饰器了,计算程序的运行时间,当然思想和以前用函数写装饰器是一样的
>>>call....#这个是执行调用这个实例化之后的方法输出的
class Fuck(object):运行结果:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
import time
start_time = time.time()
res = self.func(*args, **kwargs)
end_time = time.time()
print('the function "%s" run time is %s' % (self.func.__name__,
(end_time - start_time)))
return res
@Fuck
def run(name):
import time
time.sleep(1)
return 'sb_%s' % name
print(run('hyf'))
>>>the function "run" run time is 1.0001001358032227#这个是装饰器帮我们计算的函数运行时间原文地址:http://www.nnzhp.cn/blog/2017/01/16/1/
>>>sb_hyf#这个是正常运行run函数的时候,返回的值