We can become blind by seeing each day as a similar one. -- Paolo Coelho
教程
patch_all 不是一个好主意
- gevent.monkey.patch_all() 给所有能打上 patch 的模块打上
- gevent.monkey.patch_socket() 只给 socket 模块打上
我觉得最佳的方式是,只针对你需要的模块打 patch, 否则容易造成 gevent 的滥用。
gevent tutorial 称 monkeypatching 为 dark corners of Gevent.
当然,还有更精确的使用方法,例如:
- gevent.sleep
- gevent.select
参考:
- http://www.gevent.org/gevent.monkey.html
- http://sdiehl.github.com/gevent-tutorial/
并发下载示例
import gevent.monkey
gevent.monkey.patch_socket()
import gevent
import urllib2
import simplejson as json
def fetch(pid):
response = urllib2.urlopen('http://json-time.appspot.com/time.json')
result = response.read()
json_result = json.loads(result)
datetime = json_result['datetime']
print 'Process ', pid, datetime
return json_result['datetime']
def synchronous():
for i in range(1,10):
fetch(i)
def asynchronous():
threads = []
for i in range(1,10):
threads.append(gevent.spawn(fetch, i))
gevent.joinall(threads)
print 'Synchronous:'
synchronous()
print 'Asynchronous:'
asynchronous()
race condition
协程中避免使用全局变量来进行状态统计,或者结果收集。
若要收集结果,可以使用 value 属性来获取每个 greenlet 的返回值。
何时执行
gevent.spawn 时,协程已经开始执行。 gevent.joinall 只是用来等待所有协程执行完毕。
异常处理
注意,在协程外无法通过平常的异常捕获方式获取内部异常
# Exceptions raised in the Greenlet, stay inside the Greenlet.
try:
gevent.joinall([winner, loser])
except Exception as e:
print('This will never be reached')
但是,可以通过 exception 属性获得。
所以,每个协程内的异常最好自己包住,通过错误码返回给外面。
程序退出时,如何保证所有协程也退出
为了避免僵尸进程, 需要这样
import gevent
import signal
def run_forever():
gevent.sleep(1000)
if __name__ == '__main__':
gevent.signal(signal.SIGQUIT, gevent.shutdown)
thread = gevent.spawn(run_forever)
thread.join()
urllib2 超时处理
http://www.coder4.com/archives/2192
unpatch gevent patch
为什么要 unpatch ?
首先需要证明 patch 是一个邪恶的东西
a.py
import gevent.monkey
gevent.monkey.patch_socket()
import socket
print socket.socket # <class 'gevent.socket.socket'>
b.py
import a
import socket
print socket.socket # <class 'gevent.socket.socket'>
从运行结果看,a 模块的 patch 影响到了 b 模块的 socket 模块。 而实际上,我们并不是所有时候都需要 patch 后的 socket 行为, "some tests rely on this patching, and some rely on not being patched."
如何避免这种影响呢?两种方法
- 只使用 gevent.socket, 不使用 patch
- unpatch -> reload socket module
即将 b.py 修改为
import a
import socket
reload(socket)
print socket.socket # <class 'socket._socketobject'>
参考:
- http://stackoverflow.com/questions/10990151/gevent-monkey-unpatch/10991918#10991918
- http://emptysquare.net/blog/undoing-gevents-monkey-patching/
如何限制并发的 greenlets
使用 gevent 的 pool
A pool is a structure designed for handling dynamic numbers of greenlets which need to be concurrency-limited. This is often desirable in cases where one wants to do many network or IO bound tasks in parallel.
在有大量 IO 并发的时候,需要限制并发量。同事限制在了 300. 具体根据机器性能, 测试决定。
示例代码:
- https://github.com/sunzhongwei/test_gevent/blob/master/test_pool.py
gevent.subprocess
使用 gevent.subprocess 并发调用命令
https://github.com/sunzhongwei/config/blob/master/Templates/gevent_subprocess.py
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式