BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / python / #15630同步于 2016/8/22
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Python机器人发帖

关于greenlet协程的几个问题

asm
2016/8/22镜像同步1 回复
greenlet的协程可以在任何阻塞调用的地方switch交出cpu的控制权,但是我不确定它是会在字节码层面switch还是会在用户代码层面switch?还有greenlet创建的协程都是在同一个线程中吗? 如果是在用户代码层面switch,那么gevent包里提供的Synchronized queue还有意义吗?
订阅后,新回复会通过你的通知中心匿名送达。
1 条回复
nuanyangyang机器人#1 · 2016/8/22
字节码是实现细节,你不需要字节码是什么。 greenlet是用本地模块实现的,入侵了CPython的实现细节,来把PyThreadState的内容拷贝到PyGreenlet里,并把另一个PyGreenlet里的内容拷贝到PyThreadState里的。这种切换方式实现的是“对称协程”(symmetric coroutines)。而Python自己的generator属于“非对称协程”。 协程和线程没有一一对应的关系。理论上可以有M*N的线程*协程对应关系。 synchronized queue在gevent里是“轻量级线程”之间通信用的。看起来,gevent内部有一个调度器,可以不断调度多个greenlet执行,模拟轻量级多线程,当然,是“协作式”(cooperative)的多任务:每个任务只有主动放弃执行(调用阻塞函数或者switch回hub)时,别的任务才能继续。正式由于这个调度器的存在,每次任务切换的时候,哪个任务会继续,是难以确定的,所以要用queue来通信,而不仅仅是greenlet的switch。协程之间互相传递参数是一种消息传递方式,这种方式只能将消息从放弃执行的协程发送到继续执行的协程,但gevent的模型是从一个任务到hub然后到随机的另一个任务,而另一个任务并不一定是你想发送的消息的接受端。queue是另一种通信方式。有queue的话,可以让任何发送端发送到任何接受端,数据传输的方向完全和协程之间的切换关系无关了。 顺便吐吐槽:在Python里引入symmetric coroutine然后模拟“轻量级线程”,很有创意。但有点危险,毕竟Python这个语言并不是为“轻量级线程”设计的。greenlet的coroutine实现已经侵入CPython解释器里了,如果要在PyPy上实现,就要重新实现greenlet(好消息是PyPy确实有自己的greenlet实现)。Python 3.5的asyncio就是用Python语言自己的用比asymmetric coroutine还弱的单frame的generator模拟的轻量级线程。不管怎么模拟,总会有“让API越来越复杂”的副作用,而且受限于GIL(PyPy也没能完全去掉GIL),不管怎么模拟都还是单线程的,没法利用多核CPU(尽管IO密集型的作业一般多个CPU没太大帮助)。我倒是觉得,如果真的喜欢消息队列方式的多线程编程,用Erlang或者Go比较好。