分享一下完全不依赖 asyncio 也支持异步语法的库

2021-09-07 10:15:43 +08:00
 sujin190

https://github.com/snower/sevent

异步语法的支持完全不依赖 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)
4354 次点击
所在节点    Python
59 条回复
abersheeran
2021-09-07 10:26:05 +08:00
看到了 greenlet,我之前就有个想法,用 greenlet 把同步函数包装起来变成一个 awaitable 的对象,但是一直没空去做。你可以试试看做一下。
sujin190
2021-09-07 10:38:51 +08:00
@abersheeran #1 这个很简单,很早就搞过了

https://github.com/snower/TorMySQL
封装的 pymysql 可在 asyncio 下用

https://github.com/mongodb/motor
封装的 pymongo
youngce
2021-09-07 11:02:59 +08:00
Twisted 的出现比 asyncio 还早,本质就是函数回调+事件循环。后来 Twisted 一部分核心贡献者转到 asyncio 去了,毕竟 asyncio 是未来
abersheeran
2021-09-07 11:08:14 +08:00
motor 用的线程池。你这个 TorMySQL 写的一言难尽……不过 https://github.com/snower/TorMySQL/blob/ad583aadc2844c4b4e32e948b1f3252582832022/tormysql/util.py 这个挺符合我之前的设想。测试结果怎么样?比 asyncio.to_thread 快吗?
sujin190
2021-09-07 11:11:40 +08:00
@youngce #3 你说的对,但是 Twisted 要能用 async 和 await 语法底层 ioloop 必须是 asyncio,我分享这个并没有说比 asyncio 更好,只是分享下对不使用 asyncio 的情况下如何使用 async 和 await 语法,感兴趣的话可以看看一看,毕竟 python 的 async 和 await 语法可是在解释器层和 asyncio 耦合在一起的,异步 io 相关的实现就更多了,也不复杂

而且吧其实 asyncio 为了使用更广,接口实现太复杂了,想简单搞个小工具啥的太麻烦了
Kilerd
2021-09-07 11:12:16 +08:00
sujin190
2021-09-07 11:16:01 +08:00
@abersheeran #4 motor 并没有用线程池,你没仔细看吧,greenlet 的切换肯定比线程切换快,款且还有同步锁的问题,实现要更复杂,性能肯定是 greenlet 更好了

TorMySQL 我们自己用了很久了,并没有啥问题啊,只是为了让在 python2 的 tornado 上也能正常运行,并不是全都是 python3 语法的
abersheeran
2021-09-07 11:22:11 +08:00
@sujin190 Motor 的线程池代码: https://github.com/mongodb/motor/blob/master/motor/frameworks/asyncio/__init__.py#L73

我还想问个 Greenlet 的问题:一个带系统中断操作的函数丢到 greenlet 里,它会自动在中断时 switch 到其他 greenlet 吗?
sujin190
2021-09-07 11:43:24 +08:00
@abersheeran #8 好吧,我错了,没想到 0.5 版本之后这货就改成线程池了,只是不知道为啥这样改

应该不会吧,greenlet 切换的是栈帧,系统中断打断的是底层线程调用栈,python 的栈帧似乎是分配在堆上的,线程切换并不会影响 python 栈帧,自然也就不会导致 greenlet 切换了吧
abersheeran
2021-09-07 11:46:16 +08:00
@sujin190 中断不会导致 greenlet 切换?那你这个封装甚至不如 asyncio.to_thread 快啊。我明白 motor 怎么换成线程池了。看来我还得看看 gevent 去
sujin190
2021-09-07 11:47:32 +08:00
@abersheeran #8 如果是 signal 信号打断,signal 信号处理器结束的时候会恢复原来的栈帧,所以这种估计也不会导致 greenlet 切换吧
sujin190
2021-09-07 11:52:15 +08:00
@abersheeran #10 你说的是系统 io 会不会导致 greenlet 切换吧?这个系统 io 处理都是运行在主 greenlet 里的,是你需要写数据读数据的时候,你主动切换的主 greenlet 去,不像线程池一样当系统 io 产生的时候由操作系统调度线程切换
ysc3839
2021-09-07 12:06:50 +08:00
借楼问一下,Python 里 async function 能否当成回调函数使用?
比如说已经有一个队列了,在 await 某个对象时得到一个回调函数加入队列,后续执行这个函数恢复 async function 执行。
abersheeran
2021-09-07 12:09:25 +08:00
@sujin190 那只要一个 SQL 查询卡在那儿,后续所有 SQL 查询不都被阻塞了吗?
sujin190
2021-09-07 12:16:44 +08:00
@abersheeran #14 不啊,主 greenlet 使用 epoll 可以同时处理很多个连接的,连接 io 事件产生的时候主 greenlet 处理完事件后会依次切换到对应的子 greenlet 做业务处理,子 greenlet 又可以产生更多的 io 操作主动切回主 greenlet 处理了啊,这样不就异步并行可以同时处理无数个 sql 查询请求了
abersheeran
2021-09-07 12:30:40 +08:00
@sujin190 😦好的我去看看
sujin190
2021-09-07 12:35:06 +08:00
@ysc3839 应该是可以的吧,只不过普通队列并不能让这个函数运行起来,你需要从队列取出来后扔到 asyncio 中去运行起来
ysc3839
2021-09-07 13:05:15 +08:00
@sujin190 想问不用 asyncio 的情况能否实现。
sujin190
2021-09-07 13:40:55 +08:00
@ysc3839 #18 也是可以的,只是不用 asyncio 这样的异步 io,那么异步方法似乎没啥用了吧,没啥用的必要了
tmac010sjh
2021-09-07 15:19:11 +08:00
苏神依旧这么牛逼,还在 mg 么?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/800308

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX