让你快速的了解什么是协程

python-gevent

Posted by TuoX on November 29, 2017

概述

说到多进程,多线程,也许大家都不陌生。但是说到协程,未必是家喻户晓。

什么是协程(coroutine)?说到协程,必须说到子例程(或者说是函数)。

在所有的语言中,程序都是层级调用的。

比如说程序A调用了程序B,程序B又调用了程序C,执行的顺序为程序C执行完毕,程序B执行完毕,最后程序A执行完毕。

协程类似于子例程,但是与子例程不同的是,子例程执行中程序B不可以中断,但是协程可以,可以中断某个程序,转而执行另外的程序。


这么说的话,大家是不是觉得协程还类似于多线程呢,但是协程只是一个线程的执行。

协程比起多线程的优势非常明显(重点体现于执行效率),可以概括成两个点:

1.协程是程序内部切换,而不是像多线程一样系统级别的切换。

2.协程没有像多线程一样的,线程之间的锁。

所以现在越来越多的程序,站点,倾向于多进程加协程,而不是多进程加多线程。


那在python中协程是如何实现的呢,python的协程发展历史挺长的,从yield/send到async/await。

今天不讨论这些是如何实现的,主要讨论下python协程的第三方库gevent。

What is gevent?

gevent is a coroutine -based Python networking library that uses greenlet to provide a high-level synchronous API on top of the libev event loop.

Features include:

Fast event loop based on libev (epoll on Linux, kqueue on FreeBSD).
Lightweight execution units based on greenlet.
API that re-uses concepts from the Python standard library (for example there are gevent.event.Events and gevent.queue.Queues).
Cooperative sockets with SSL support.
DNS queries performed through threadpool or c-ares.
Monkey patching utility to get 3rd party modules to become cooperative.

以上是从官网复制过来的介绍。大概意思是这样的:

gevent是一个基于协同程序的Python网络库,它使用 greenlet在libev事件循环之上提供高级同步API。

功能包括:

基于libev的快速事件循环(Linux上的epoll,FreeBSD上的kqueue)。
基于greenlet的轻量级执行单元。
重用Python标准库中的概念的API(例如有gevent.event.Events和gevent.queue.Queues)。
具有SSL支持的合作套接字。
通过线程池或c-ares执行DNS查询。
猴子修补工具让第三方模块变成更加友好。

基本思想是:当一个greenlet遇到一个IO操作,比如打开一个网页,那么它就会切换到其他的greenlet,等待IO操作完毕,再在适当的时候切换回来。保证总是有greenlet在运行,而不是一直等待IO操作。

代码层面

我们看一个例子:

from gevent import monkey
monkey.patch_all()
import gevent
import requests


def f(url):
    print(url)
    response = requests.get(url).text
    print('%s len=%d' % (url, len(response)))


gevent.joinall([
    gevent.spawn(f, 'https://www.python.org/'),
    gevent.spawn(f, 'https://www.github.com/'),
    gevent.spawn(f, 'https://www.baidu.com/'),
])
https://www.python.org/
https://www.github.com/
https://www.baidu.com/
https://www.baidu.com/ len=2443
https://www.python.org/ len=48856
https://www.github.com/ len=51350

我们发现访问速度最快的百度最先得出结果,而不是按照执行的顺序来输出结果的。这就是协程的魅力。

部署层面

协程还可以应用在服务器部署上

今天跟大家介绍gunicorn加gevent的方式,让web站点性能变得更加的极致。

gunicorn原生就支持gevent的方式,所以我们只需要安装下gevent,指定下配置就可以了。

有两种安装方式:

1.apt-get install python-gevent
2.pip install gevent

安装完了之后配置也很方便,参数上加上-k gevent就行了(默认是sync)。

1.flask

gunicorn -w 4 -b 0.0.0.0:7000 -k gevent app:app # app.py中的app模块(启动4个进程并且ip端口为0.0.0.0:7000)

2.Django

gunicorn -w 4 -b 0.0.0.0:7070 -k gevent ***.wsgi:application # ***表示django项目名称(每个django项目,会在根目录下创建一个跟项目名称一样名字的文件夹)

gunicorn基本上是搭配nginx+supervisor一起使用,gunicorn作为wsgi托管、supervisor作为进程守护,nginx作为反向代理等。更多相关的配置可以看我之前写的文章gunicorn&supervisor&nginx

The End

希望这篇文章能够给予正在查找gevent资料的小伙伴一些帮助。