文章思路:本文将先介绍协程的概念,然后分别介绍Python2.x与3.x下协程的用法,最终将协程与多线程做比较并介绍异步爬虫模块。
协程
概念
协程,又称微线程,纤程,英文名Coroutine。协程的作用,是在执行函数A时,可以随时中断,去执行函数B,然后中断继续执行函数A(可以自由切换)。但这一过程并不是函数调用(没有调用语句),这一整个过程看似像多线程,然而协程只有一个线程执行。
进群:548377875 即可获取数十套PDF哦!
Python2.x协程
python2.x协程应用:
- yield
- gevent
python2.x中支持协程的模块不多,gevent算是比较常用的,这里就简单介绍一下gevent的用法。
Gevent
gevent是第三方库,通过greenlet实现协程,其基本思想:
当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。
运行结果:
start 0
start 1
start 2
end 2
end 0
end 1
说明:从结果上来看,执行get_body的顺序应该先是输出”start”,然后执行到urllib2时碰到IO堵塞,则会自动切换运行下一个程序(继续执行get_body输出start),直到urllib2返回结果,再执行end。也就是说,程序没有等待urllib2请求网站返回结果,而是直接先跳过了,等待执行完毕再回来获取返回值。值得一提的是,在此过程中,只有一个线程在执行,因此这与多线程的概念是不一样的。
Gevent使用说明
- monkey可以使一些阻塞的模块变得不阻塞,机制:遇到IO操作则自动切换,手动切换可以用gevent.sleep(0)(将爬虫代码换成这个,效果一样可以达到切换上下文)
- gevent.spawn 启动协程,参数为函数名称,参数名称
- gevent.joinall 停止协程
Python3.x协程
为了测试Python3.x下的协程应用,我在virtualenv下安装了python3.6的环境。
python3.x协程应用:
- asynico + yield from(python3.4)
- asynico + await(python3.5)
- gevent
Python3.4以后引入了asyncio模块,可以很好的支持协程。
asynico
asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。asyncio的异步操作,需要在coroutine中通过yield from完成。
说明:从运行结果可以看到,跟gevent达到的效果一样,也是在遇到IO操作时进行切换(所以先输出test_1,等test_1输出完再输出test_2)。但此处我有一点不明,test_1的输出为什么不是按照顺序执行的呢?可以对比gevent的输出结果(希望大神能解答一下)。
Usage
例子(python3.5以后版本使用):
gevent
同python2.x用法一样。
协程VS多线程
如果通过以上介绍,你已经明白多线程与协程的不同之处,那么我想测试也就没有必要了。因为当线程越来越多时,多线程主要的开销花费在线程切换上,而协程是在一个线程内切换的,因此开销小很多,这也许就是两者性能的根本差异之处吧。(个人观点)
异步爬虫
也许关心协程的朋友,大部分是用其写爬虫(因为协程能很好的解决IO阻塞问题),然而我发现常用的urllib、requests无法与asyncio结合使用,可能是因为爬虫模块本身是同步的(也可能是我没找到用法)。那么对于异步爬虫的需求,又该怎么使用协程呢?或者说怎么编写异步爬虫?
- grequests (requests模块的异步化)
- 爬虫模块+gevent(比较推荐这个)
- aiohttp (这个貌似资料不多,目前我也不太会用)
- asyncio内置爬虫功能 (这个也比较难用)
协程池
作用:控制协程数量
get去吧!
原文链接:https://www.f2er.com/python/58976.html