协程

协程一个简单实现

import time

def A():
    while True:
        print("----A---")
        yield
        time.sleep(0.5)

def B(c):
    while True:
        print("----B---")
        c.next()
        time.sleep(0.5)

if __name__=='__main__':
    a = A()
    B(a)

协程-greenlet版

为了更好使用协程来完成多任务,python中的greenlet模块对其封装,从而使得切换任务变的更加简单

安装方式

使用如下命令安装greenlet模块:

    sudo pip install greenlet

  

from greenlet import greenlet

import time


def demo1():
    while 1:
        print('---A---')
        gr2.switch()
        time.sleep(0.5)


def demo2():
    while 1:
        print('---B---')
        gr1.switch()
        time.sleep(0.5)

gr1 = greenlet(demo1)
gr2 = greenlet(demo2)

gr1.switch()
greenlet协程Code

gevent

greenlet已经实现了协程,但是这个还的人工切换,是不是觉得太麻烦了,不要捉急,python还有一个比greenlet更强大的并且能够自动切换任务的模块gevent

其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。

由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO

 

gevent切换执行

import gevent
import time

def f(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        gevent.sleep(0.5)  # 注意这里的sleep为gevent的sleep函数

g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)


g1.join()
g2.join()
g3.join()
gevent自动切换Code

gevent并发下载器

当然,实际代码里,我们不会用gevent.sleep()去切换协程,而是在执行到IO操作时,gevent自动切换,代码如下

 1 import requests
 2 import gevent
 3 from gevent import monkey
 4 
 5 monkey.patch_all()  # 动态替换了涉及io操作的函数,,,当遇到阻塞时自动切换
 6 
 7 def download(url, file):
 8     response = requests.get(url)
 9     with open(file, 'w') as f:
10         f.write(response.content.decode())
11     # 打印url,,,对应的字节码数
12     print('url----{}, bytes----{}'.format(url, len(response.content.decode())), response.status_code)
13 
14 
15 # 全部阻塞
16 gevent.joinall([
17     gevent.spawn(download, 'https://www.sina.com', 'sina.html'),
18     gevent.spawn(download, 'http://www.126.com', '126.html'),
19     gevent.spawn(download, 'https://www.baidu.com', 'baidu.html'),
20 
21 ])
并发下载器Code

结果:

url----https://www.baidu.com, bytes----2349 200
url----http://www.126.com, bytes----105166 200
url----https://www.sina.com, bytes----562122 200

  从上能够看到是先发送的获取baidu的相关信息,然后依次是126,sina,但是收到数据的先后顺序不一定与发送顺序相同,这也就体现出了异步,即不确定什么时候会收到数据,顺序不一定

 强化理解    利用猴子黑科技动态地将IO操作库中的函数替换成gevent 自己的函数,之后再次遇到io阻塞操作时自动切换。执行

优点:不存在资源竞争

缺点:手动调用

gevent版-TCP服务器

 1 import sys
 2 import time
 3 import gevent
 4 
 5 from gevent import socket,monkey
 6 monkey.patch_all()
 7 
 8 def handle_request(conn):
 9     while True:
10         data = conn.recv(1024)
11         if not data:
12             conn.close()
13             break
14         print("recv:", data)
15         conn.send(data)
16 
17 
18 def server(port):
19     s = socket.socket()
20     s.bind(('', port))
21     s.listen(5)
22     while True:
23         cli, addr = s.accept()
24         gevent.spawn(handle_request, cli)
25 
26 if __name__ == '__main__':
27     server(7788)
View Code

 进程vs线程vs协程

进程   并行执行    无序

线程   一次一个并发执行  无序

协程   一次一个手动挑用   手动调用

posted @ 2017-09-02 20:49  凯哥吧  阅读(120)  评论(0)    收藏  举报