一直在用 multiprocessing 和 threading ,遇到内存、资源消耗等问题,想要用gevent.spawn()
改写。
我的主进程是一个 rpc 服务器(不能被阻塞),我只想要异步执行一段代码,不想要结果(代码片段会调用 client 通知结果给主进程), 如果用join 会阻塞。
看了一篇文章 http://www.jianshu.com/p/571db0eb95f8 作者说道:
我在 Python shell 中 gevent.spawn 一个函数,它怎么不运行? 按照自然的思维就是 spawn 后就应该要运行啊。 Erlang 就是这样的
为什么 spawn 出的协程要 join ,一调用 join 就会把整个 python process 阻塞住。丝毫感觉不到异步啊。
在学习两次失败后,后来终于想明白了:
shell 中 spawn 不运行,是因为 gevent 的 event loop 没有跑起来,无法去调度 greenlet 。
join 就是在启动 gevent 的 gevent loop ,一旦 gevent loop 通过其他方式启动起来了, 那么就可以在程序中自然的 spawn 进程。新 spawn 的 greenlet 会被调度执行。
当跨过这个障碍后,学习和使用 Gevent 容易了很多。
很想知道怎样启动 gevent loop ,可以让我新的 spawn 自动异步运行? 尝试了以下代码
gevent.spawn(task)
gevent.sleep(0)
可以跑通,但是 task 函数内如果有 gevent.sleep(2), grequest 之类的语句,就会出现跑一半不跑了的情况,觉得不靠谱会这样那样的意外,因为我没有办法干涉 task 函数。
这让我感觉到 gevent 在 python 大型应用程序的使用率应该很低,要么全部都用,要么全部都不能用,大部分团队多半会选择后者。
想的有点多了,不知道是不是这样呢
1
GeekGao 2016-10-20 17:20:00 +08:00
“是因为 gevent 的 event loop 没有跑起来,无法去调度 greenlet ” 你确定是这个原因? spawn 一个函数,函数里内容是啥?
|
2
tomzhu OP @GeekGao 所以我必须要知道函数的内容才能用 gevent.spawn 吗? FYI, 函数内容是调用 client 给 rpc 服务器发送请求并获取返回,这个请求可能瞬间也可能需要数秒,取决于服务器怎么处理。
|
3
yufpga 2016-10-20 17:54:23 +08:00
先找到程序中被阻塞部分, 改为非阻塞的.
|
4
tomzhu OP @yufpga 问:怎么改?答:用 gevent.spawn 。"又回到最初的起点,呆呆的站在镜子前,笨拙#~*&(@$!#$^@#%!~"
|
5
neoblackcap 2016-10-20 18:06:53 +08:00
@tomzhu 你需要了解 Linux 编程里面的 IO 操作, gevent.spawn 只是一个封装,你大可用系统调用 ioctl 将 fd 设成非堵塞,那么所有的读都是非堵塞的了
|
6
yufpga 2016-10-20 18:14:35 +08:00
我不知道你的程序阻塞在哪了, 建议先看一下 gevent 的猴子补丁部分的内容(会让你对这个问题出现的原因有个大概的认知), 如果猴子补丁并不能解决你阻塞的问题, 建议还是换一个方案.当然, 阻塞变非阻塞不是 gevent.spawn 干的事.
|
8
fds 2016-10-20 18:21:22 +08:00
好几年没用了。不过我印象中 gevent 是协作式的并行,同一时刻只能有一个协程运行,必须由它主动让出自己的执行状态,换成别的协程。
所以如果某一协程要做网络调用,那么应该在发起非阻塞请求,然后让出执行权,等待别人再把执行权交给回自己。 一般都是通过 monkey patch ,把 python 的一些库函数包装成使用 gevent 的。但有些没包装的,就可能会阻塞了,要自己改。 |
9
binux 2016-10-20 18:29:08 +08:00
你是不是理解错了什么, gevent 并不能让你的程序「异步」运行,它只能帮你在 event wait 时切换协程罢了。
例如你的 task 是计算型的,没有 event wait 或者主线程不将执行权限交还给 gevent (例如 gevent.sleep ),它怎么切换?怎么去执行其他的协程? |
10
binux 2016-10-20 18:29:50 +08:00
所以,该用进程或者线程的时候就要用啊。
|
11
neoblackcap 2016-10-20 18:38:39 +08:00
@binux 我觉得,还是先推荐读 UNP 比什么都重要,读后才开始“异步”编程,否则一个 sleep ,或者 gevent 里面写日志到本地文件,就全线爆炸了。
太多新人根本不了解所谓的异步,同步,堵塞,非堵塞然后就开始上各种框架,这是一切的问题的根源啊。 |
12
tomzhu OP 看了这么多回复,原来 gevent 并不能让我异步化,我还是继续用 threading 吧,谢谢大家!
|
13
tomzhu OP @yufpga 我的程序阻塞在 task 函数里面。猴子补丁会让我的应用程序充满不确定性,除非我很清楚他究竟 monkeypatch 了哪些模块,否则我不会用的
|
15
neoblackcap 2016-10-20 19:21:16 +08:00
@tomzhu 不用 monkeypatch.patch_all(),你可以自己一个一个 patch ,具体 patch 了什么 https://github.com/gevent/gevent/blob/master/src/gevent/monkey.py#L575
两大切记, gevent 在面对 CPU 密集型以及本地 IO 密集型的任务,都很无力 |