Tag Archives:Python

Python 的 asyncio 网络性能比 C 写的 Redis 还好?

先前我做过一个 asyncio/gevent 的性能比较《性能测试:asyncio vs gevent vs native epoll》,今天修改了一下 asyncio 的测试程序的消息解析部分,改用 Protocol,发现它甚至比 redis 还快了:

安装依赖:

pip install hiredis uvloop

编辑 echosvr.py 文件:

Continue reading

Loading

性能测试:asyncio vs gevent vs native epoll

测试一下 python 的 asyncio 和 gevent 的性能,再和同等 C 程序对比一下,先安装依赖:

pip3 install hiredis gevent

如果是 Linux 的话,可以选择安装 uvloop 的包,可以测试加速 asyncio 的效果。

测试程序:echo_bench_gevent.py

import sysimport geventimport gevent.monkeyimport hiredisfrom gevent.server import StreamServergevent.monkey.patch_all()d = {}def process(req):    # only support get/set    cmd = req[0].lower()    if cmd == b'set':        d[req[1]] = req[2]        return b"+OK\r\n"    elif cmd == b'get':        v = d.get(req[1])        if v is None:            return b'$-1\r\n'        else:            return b'$1\r\n1\r\n'    else:        print(cmd)        raise NotImplementedError()    return b''def handle(sock, addr):    reader = hiredis.Reader()    while True:        buf = sock.recv(4096)        if not buf:            return        reader.feed(buf)        while True:            req = reader.gets()            if not req:                break            sock.sendall(process(req))    return 0print('serving on 0.0.0.0:5000')server = StreamServer(('0.0.0.0', 5000), handle)server.serve_forever()

测试程序:echo_bench_asyncio.py

(点击 Read more 展开)

Continue reading

Loading

怎么样打包 pyqt 应用才是最佳方案?

早先看一堆人说 PyQt 打包麻烦,部署困难的,打出来的包大(几十兆起步),而且启动贼慢,其实 Python+PyQt 打包非常容易,根本不需要用什么 PyInstaller,我手工打包出来的纯 Python 环境只有 5MB,加上 PyQt 也才 14MB。

很多人用 PyInstaller 喜欢加一个 -F 参数,打包成一个单文件:

这样的单文件看起来似乎很爽,其实他们不知道,这其实是一个自解压程序,每次运行时需要把自己解压到 temp 目录,然后再去用实际的方式运行一遍解压出来的东西:

Process Explorer 把雷达图标拖动到 pyqt_hello.exe 的窗口上,可以看到有两个 pyqt_hello.exe 的文件,外面那个是你打包出来的,里面那个才是真正的程序(虽然可执行都是一个),看看它下面依赖的 python310.dll 是在哪里?这不就是一个临时解压出来的目录么:

看到没?这就是你 PyInstaller 打包出来的 30MB 的程序,每次运行都要临时解压出 71MB 的文件,运行完又删除了,那么如果打包出来的可执行有 100MB,每次运行都要释放出 200-300 MB 的东西出来,所以为什么 PyInstaller 出来的单文件运行那么慢的原因除了每次要解压外,还有杀毒软件碰到新的二进制都要扫描一遍,你每次新增一堆 .dll , .pyd, .exe,每次都要扫描,不慢可能么?

其实 PyInstaller 如果不打包成单文件可执行(-F 参数),用起来问题不大,唯一不足有两个,首先是很多动态库其实我没用比如上面的 socket, ssl, QtQuick 等,但都被打包的时候打进去了,大小会偏大;其次是目录看起来很乱,上百个文件一个目录,找主程序都找不到。

正确的打包姿势

当然是手工打包,现在 Python 3.5 以后,官方都会发布一个嵌入式 Python 包:

链接在这里:Python Release Python 3.8.10

(点击 more/continue 继续)

Continue reading

Loading

桌面开发用 Tkinter/wxPython/PyQt 哪个好?

Python 有很多 GUI 框架,比如著名的 Tkinter,wxPython 和 PyQt,那么想用 Python 开发桌面软件的话选哪个更好呢?作为三个都用过的人先给个结论,不用纠结,直接选 PyQt 即可。

很多人说 Tkinter 简单无依赖,没错,但这就是 tkinter 唯一的仅存的优点了,但是请大家注意,Tkinter 的这个 “简单”,是指 “功能少和效果单一”,不是写程序简单明了,真正写起程序来还是 PyQt 最简单清晰。

有些东西你学出来就过时了,比如 “算盘”,比如 Tkinter 和 wxPython;而有的东西你学会了,即便不吃这碗饭,不靠它涨工资,也能在今后一二十年持续受益,比如练习打字速度,比如背单词,比如学习 PyQt。

对于桌面开发,天下武功那么多,PyQt 既是最正统的门派,同时又是一系列综合技术的组合,它近可以同 C++ Qt 无缝整合,解决性能相关的东西;退,又有基于 chromium 的 QtWebEngine ,能在适合跑页面的部分用 html/js 来写页面,并和 python 双向调用,实现类似 cef/Electron 的效果,但是 Electron 这类单一解决方案就只能用 web 技术,想反过来同 native 界面混合开发,基本就傻了,碰到性能问题又不能像 PyQt 那样可以无缝切换 C++ Qt,所以庞然大物 Electron 只适合呆在自己的舒适区。

往左,QtWidgets 可以和传统 C# 的 WinForm pk,往右,Qt-Quick 可以同 WPF/XAML 看齐,因此你可以把 PyQt/Qt 看成一系列界面解决方案的 “超集”,所以学习 PyQt 你学会的是综合格斗术,是名门正派的内功心法,而不是某方向单一的方案,比如 “螳螂拳”。

PyQt 就是一扇门,它通往的是最专业的桌面解决方案的世界。

看了不少挺 Tkinter 的,他们用 Tkinter 用的都太浅了,知乎上有个最高赞用 Tkinter 费力拙略地模仿了个背单词的 anki,也许他不知道,他所模仿的 anki 其实本身就是用 PyQt 开发的。

真的用的深的只有这个回答:
为何很多Python开发者写GUI不用Tkinter,而要选择PyQt和wxPython或其他?

我曾经用 Tkinter 做过一些内部工具,比如给线上网络服务做的一个 RPC 调试终端:

当时我就是图别的同事使用时不用装其他库,结果写到后面,越做越后悔。

(点击 continue/more 继续)

Continue reading

Loading

PY2EXE的启动步奏参考-科学的发布

周末读了一下Py2Exe的代码,偶然发现Py2Exe的实现,是一套很成熟的客户端发布方式,不限于只有 Python项目可以参考,Py2exe启动步奏如下: Py2exe启动步奏方式参考:

  1. 主程序启动,尝试在本EXE的资源中找到zip过后的PythonXX.dll的数据
  2. 如果找到 PythonXX.dll数据则unzip后以memory dll方式加载并导出接口
  3. 初始化 memoryimporter,给python提供在内存中import一个pyc或者dll的功能
  4. 利用memoryimporter加载 ctypes.pyd模块
  5. 利用py2exe_util.c中的方法,加载程序所需要的资源:ICON等
  6. 在资源中初始化 zlib.pyd等必要模块
  7. 在资源中找到初始化,以__main__ 的命名开始转入Python脚本

Loading

Python少打字小技巧

说明:增加代码的描述力,可以成倍减少你的LOC,做到简单,并且真切有力
观点:少打字=多思考+少出错,10代码行比50行更能让人明白,以下技巧有助于提高5倍工作效率

1. 交换变量值时避免使用临时变量:(cookbook1.1)

老代码:我们经常很熟练于下面的代码

temp = xx = yy = temp

代码一:

u, v, w = w, v, u

有人提出可以利用赋值顺序来简化上面的三行代码成一行

代码二:

u, v = v, u

其实利用Python元组赋值的概念,可更简明 — 元组初始化 + 元组赋值

2. 读字典时避免判断键值是否存在:(cookbook1.2)

d = { 'key': 'value' }

老代码:

if 'key' in d: print d['key']else: print 'not find'

新代码:

print d.get('key', 'not find')

Continue reading

Loading