分享一下完全不依赖 asyncio 也支持异步语法的库
异步语法的支持完全不依赖 asyncio,当然并没有说可以替代 asyncio 或者更好啥的,只是一种实现,如果有对异步 io 或者 python 异步语法实现感兴趣的可以一看吧。
只要是用于代理流量转发这样的场景,所以接口毕竟简单,当然支持范围也就没 asyncio 那么广了,从 echo 测试来看,性能还是要好于 asyncio 一些的,helpers 中也简单实现了几个工具。
HTTP 请求测试
import sevent
async def http_test():
s = sevent.tcp.Socket()
await s.connectof((‘www.baidu.com’, 80))
await s.send(b’GET / HTTP/1.1\r\nHost: www.baidu.com\r\nConnection: Close\r\nUser-Agent: curl/7.58.0\r\nAccept: */*\r\n\r\n’)
data = b”
while True:
try:
data += (await s.recv()).read()
except sevent.tcp.SocketClosed:
break
print(data.decode(“utf-8”))
await s.closeof()
sevent.run( http_test)
TCP 端口转发
import sys
import sevent
async def tcp_port_forward_server():
server = sevent.tcp.Server()
server.listen((“0.0.0.0”, int(sys.argv[1])))
while True:
conn = await server.accept()
pconn = sevent.tcp.Socket()
pconn.connect((sys.argv[2], int(sys.argv[3])))
conn.link(pconn)
sevent.run(tcp_port_forward_server)
await asyncio 异步 Python25 条回复 • 2021-09-07 16:10:23 +08:00
abersheeran 1
abersheeran 6 小时 32 分钟前
看到了 greenlet,我之前就有个想法,用 greenlet 把同步函数包装起来变成一个 awaitable 的对象,但是一直没空去做。你可以试试看做一下。
sujin190 2
sujin190 6 小时 19 分钟前
@abersheeran #1 这个很简单,很早就搞过了
https://github.com/snower/TorMySQL
封装的 pymysql 可在 asyncio 下用
https://github.com/mongodb/motor
封装的 pymongo
youngce 3
youngce 5 小时 55 分钟前
Twisted 的出现比 asyncio 还早,本质就是函数回调+事件循环。后来 Twisted 一部分核心贡献者转到 asyncio 去了,毕竟 asyncio 是未来
abersheeran 4
abersheeran 5 小时 50 分钟前
motor 用的线程池。你这个 TorMySQL 写的一言难尽……不过 https://github.com/snower/TorMySQL/blob/ad583aadc2844c4b4e32e948b1f3252582832022/tormysql/util.py 这个挺符合我之前的设想。测试结果怎么样?比 asyncio.to_thread 快吗?
sujin190 5
sujin190 5 小时 47 分钟前
@youngce #3 你说的对,但是 Twisted 要能用 async 和 await 语法底层 ioloop 必须是 asyncio,我分享这个并没有说比 asyncio 更好,只是分享下对不使用 asyncio 的情况下如何使用 async 和 await 语法,感兴趣的话可以看看一看,毕竟 python 的 async 和 await 语法可是在解释器层和 asyncio 耦合在一起的,异步 io 相关的实现就更多了,也不复杂
而且吧其实 asyncio 为了使用更广,接口实现太复杂了,想简单搞个小工具啥的太麻烦了
Kilerd 6
Kilerd 5 小时 46 分钟前
可以看看这个 https://github.com/dabeaz/curio
sujin190 7
sujin190 5 小时 42 分钟前
@abersheeran #4 motor 并没有用线程池,你没仔细看吧,greenlet 的切换肯定比线程切换快,款且还有同步锁的问题,实现要更复杂,性能肯定是 greenlet 更好了
TorMySQL 我们自己用了很久了,并没有啥问题啊,只是为了让在 python2 的 tornado 上也能正常运行,并不是全都是 python3 语法的
abersheeran 8
abersheeran 5 小时 36 分钟前
@sujin190 Motor 的线程池代码: https://github.com/mongodb/motor/blob/master/motor/frameworks/asyncio/__init__.py#L73
我还想问个 Greenlet 的问题:一个带系统中断操作的函数丢到 greenlet 里,它会自动在中断时 switch 到其他 greenlet 吗?
sujin190 9
sujin190 5 小时 15 分钟前
@abersheeran #8 好吧,我错了,没想到 0.5 版本之后这货就改成线程池了,只是不知道为啥这样改
应该不会吧,greenlet 切换的是栈帧,系统中断打断的是底层线程调用栈,python 的栈帧似乎是分配在堆上的,线程切换并不会影响 python 栈帧,自然也就不会导致 greenlet 切换了吧
abersheeran 10
abersheeran 5 小时 12 分钟前
@sujin190 中断不会导致 greenlet 切换?那你这个封装甚至不如 asyncio.to_thread 快啊。我明白 motor 怎么换成线程池了。看来我还得看看 gevent 去
sujin190 11
sujin190 5 小时 11 分钟前
@abersheeran #8 如果是 signal 信号打断,signal 信号处理器结束的时候会恢复原来的栈帧,所以这种估计也不会导致 greenlet 切换吧
sujin190 12
sujin190 5 小时 6 分钟前
@abersheeran #10 你说的是系统 io 会不会导致 greenlet 切换吧?这个系统 io 处理都是运行在主 greenlet 里的,是你需要写数据读数据的时候,你主动切换的主 greenlet 去,不像线程池一样当系统 io 产生的时候由操作系统调度线程切换
ysc3839 13
ysc3839 4 小时 51 分钟前 via Android
借楼问一下,Python 里 async function 能否当成回调函数使用?
比如说已经有一个队列了,在 await 某个对象时得到一个回调函数加入队列,后续执行这个函数恢复 async function 执行。
abersheeran 14
abersheeran 4 小时 49 分钟前
@sujin190 那只要一个 SQL 查询卡在那儿,后续所有 SQL 查询不都被阻塞了吗?
sujin190 15
sujin190 4 小时 42 分钟前
@abersheeran #14 不啊,主 greenlet 使用 epoll 可以同时处理很多个连接的,连接 io 事件产生的时候主 greenlet 处理完事件后会依次切换到对应的子 greenlet 做业务处理,子 greenlet 又可以产生更多的 io 操作主动切回主 greenlet 处理了啊,这样不就异步并行可以同时处理无数个 sql 查询请求了
abersheeran 16
abersheeran 4 小时 28 分钟前
@sujin190 ?好的我去看看
sujin190 17
sujin190 4 小时 23 分钟前 via Android
@ysc3839 应该是可以的吧,只不过普通队列并不能让这个函数运行起来,你需要从队列取出来后扔到 asyncio 中去运行起来
ysc3839 18
ysc3839 3 小时 53 分钟前 via Android
@sujin190 想问不用 asyncio 的情况能否实现。
sujin190 19
sujin190 3 小时 17 分钟前
@ysc3839 #18 也是可以的,只是不用 asyncio 这样的异步 io,那么异步方法似乎没啥用了吧,没啥用的必要了
tmac010sjh 20
tmac010sjh 1 小时 39 分钟前
苏神依旧这么牛逼,还在 mg 么?
wamson 21
wamson 1 小时 32 分钟前
正好对这个有兴趣,话说这个有什么比较有名的方案吗?比如底层是 c++,io_loop 是 lib_event,通过 pybind11 来驱动 python 脚本层级,那么 python 层该怎么使用 async 语法糖呢。眼馋 python 的 async 语法糖好久了。
haoliang 22
haoliang 1 小时 2 分钟前
没有文档,粗略爬过代码;我的理解中,`sevent.go(callback)` 对应 `asyncio.create_task`, 在 sevent 中如何等待这个 callback 的完成呢? callback 运行过程中抛错,该如何处理?
sujin190 23
sujin190 50 分钟前
@wamson #21 async 语法糖本质就是一个迭代器,用迭代器的方法驱动运行就好了,搞 c++的话,去瞅一下 asyncio 的源码很快就知道了吧,而且你可以把 asyncio 的那部分源码搬过来放到你的 c++代码里啊
sujin190 24
sujin190 48 分钟前
@haoliang #22 只是一看,没啥动力写文档啊,callback 出错只是单纯用 logging 输出调用栈信息了,其实一般来说如果你关注 callback 出的错,那么你应该在一进入 callback 时就自己加 try 就是了呀
sujin190 25
sujin190 48 分钟前
@tmac010sjh #20 跑人了