Python协程

2020-06-19 00:00:00 执行 线程 爬虫 多线程 切换
真正有知识的人的成长过程,就像麦穗的成长过程:麦穗空的时候,麦子长得很快,麦穗骄傲地高高昂起,但是,麦穗成熟饱满时,它们开始谦虚,垂下麦芒。 ——蒙田《蒙田随笔全集》

  上篇论述了关于python多线程是否是鸡肋的问题,得到了一些网友的认可,当然也有一些不同意见,表示协程比多线程不知强多少,在协程面前多线程算是鸡肋。好吧,对此我也表示赞同,然而上篇我论述的观点不在于多线程与协程的比较,而是在于IO密集型程序中,多线程尚有用武之地。   对于协程,我表示其效率确非多线程能比,但本人对此了解并不深入,因此近几日参考了一些资料,学习整理了一番,在此分享出来仅供大家参考,如有谬误请指正,多谢。


申明:本文介绍的协程是入门级别,大神请绕道而行,谨防入坑。

文章思路:本文将先介绍协程的概念,然后分别介绍Python2.x与3.x下协程的用法,终将协程与多线程做比较并介绍异步爬虫模块。

协程

概念

协程,又称微线程,纤程,英文名Coroutine。协程的作用,是在执行函数A时,可以随时中断,去执行函数B,然后中断继续执行函数A(可以自由切换)。但这一过程并不是函数调用(没有调用语句),这一整个过程看似像多线程,然而协程只有一个线程执行。

优势

  • 执行效率极高,因为子程序切换(函数)不是线程切换,由程序自身控制,没有切换线程的开销。所以与多线程相比,线程的数量越多,协程性能的优势越明显。
  • 不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在控制共享资源时也不需要加锁,因此执行效率高很多。

  说明:协程可以处理IO密集型程序的效率问题,但是处理CPU密集型不是它的长处,如要充分发挥CPU利用率可以结合多进程+协程。

以上只是协程的一些概念,可能听起来比较抽象,那么我结合代码讲一讲吧。这里主要介绍协程在Python的应用,Python2对协程的支持比较有限,生成器的yield实现了一部分但不完全,gevent模块倒是有比较好的实现;Python3.4以后引入了asyncio模块,可以很好的使用协程。

Python2.x协程

python2.x协程应用: yield gevent

python2.x中支持协程的模块不多,gevent算是比较常用的,这里就简单介绍一下gevent的用法。

Gevent

gevent是第三方库,通过greenlet实现协程,其基本思想:   当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

Install

pip install gevent 新版貌似支持windows了,之前测试好像windows上运行不了......

Usage

首先来看一个简单的爬虫例子:

#! -*- coding:utf-8 -*-

import gevent
from gevent import monkey;monkey.patch_all()
import urllib2

def get_body(i):
    print "start",i
    urllib2.urlopen("http://cn.bing.com")
    print "end",i

tasks=[gevent.spawn(get_body,i) for i in range(3)]
gevent.joinall(tasks)

相关文章