由于python中的多线程比较特殊,所以协程的概念就变得尤为珍贵了,对于cpu密集型的操作,使用协程的效率无疑要好过多线程很多。因为协程的创建及其间切换的时间成本要低于线程很多。也因为这一点,很多人说,协程才是python的未来,重要不重要!!!
python中提供协程的模块有两个,greenlet和gevent。greenlet和gevent最大的区别在于greenlet需要你自己来处理线程切换, 就是说,你需要自己指定现在执行哪个greenlet再执行哪个greenlet。ps:这两个包都不是python自带的,所以需要手动安装一下,pip就可以轻松搞定!
左侧图是greenlet的用法,我已经将执行顺序标注出来了,从图中我们不难看出greenlet的执行顺序是需要我们手动控制的,现在再看看右侧的图是gevent的用法,就智能多了,它不需要我们自己去支配,只要一个协程稍有空闲,gevent就帮你进行切换,已达到cpu的最大利用率。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'Eva_J' from greenlet import greenlet def test1():
print 12
gr2.switch()
print 34
gr2.switch() def test2():
print 56
gr1.switch()
print 78 gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
greenlet Code
import gevent def foo():
print('Running in foo')
gevent.sleep(0)
print('Explicit context switch to foo again') def bar():
print('Explicit context to bar')
gevent.sleep(0)
print('Implicit context switch back to bar') gevent.joinall([
gevent.spawn(foo),
gevent.spawn(bar),
])
gevent example1 Code
这里再赠送一个gevent遇到IO操作自动切换的例子,这段代码一看就是一副高大上的样子,从老师那里偷来的,嘻:
#!/usr/bin/env python
#-*-coding:utf-8-*-
__author__ = 'Eva_J' from gevent import monkey; monkey.patch_all()
import gevent
import urllib2 def f(url):
print('GET: %s' % url)
resp = urllib2.urlopen(url)
data = resp.read()
print('%d bytes received from %s.' % (len(data), url)) gevent.joinall([
gevent.spawn(f, 'https://www.python.org/'),
gevent.spawn(f, 'https://www.yahoo.com/'),
gevent.spawn(f, 'https://github.com/'),
])
gevent example2 Code
参考文献:
python的线程进程和协成:http://www.cnblogs.com/wupeiqi/articles/5040827.html
greenlet背景介绍与实现机制:http://blog.jobbole.com/77240/