Python之协程(二十九)

      线程是CPU分配的最小单位,而进程是线程分配的最小单位,只要在线程里面的代码,才会被

CPU所执行。由于在Python的语言中,不管启动多少个线程,只能轮流被一个CPU所调度和执行,

不能像其他语言一样启动多个线程被N个CPU执行,这就是Python线程的缺陷,基于这个缺陷,也

就有了协程,在Python的语言中,线程的切换是由CPU来完成,而协程的切换是由Python代码来

切换的,这样比起线程来说,协程消耗的资源会非常小,它的控制层面完全是在用户层面控制的,

所以更加灵活。在协程中任务切换的原则是一旦遇到任务堵塞,就立刻切换,毫不犹豫,这样保证

任务一直能够执行的,除非假设一种情况就是所有的任务都堵塞,无法执行,这种情况也是存在,

但是基本出现的少。在Python中,使用协程的库分别是gevent,asyncio,下面就结合具体的案例来

说明这部分的应用。

     在gevent的库里面,切换任务使用的是switch,它的优点是规避IO的操作,这样就结合访问一个

网站系统,来看协程的案例应用,假设一个网站可以访问,另外一个不可以访问,来看应用,案例

代码如下:

#!/usr/bin/env python
# -*-coding:utf-8 -*-


import  gevent
import  time as t
from gevent import  monkey
monkey.patch_all()
import  requests

def get_wuya():
    print('开始访问无涯课堂')
    r=requests.get('http://www.wuya.com')
    print(r.status_code)
    print('访问无涯课堂结束')

def get_baidu():
    print('开始访问百度')
    t.sleep(2)
    r=requests.get('http://www.baidu.com')
    print(r.status_code)
    print('访问百度结束')


g1=gevent.spawn(get_wuya)
g2=gevent.spawn(get_baidu)
g1.join()
g2.join()

 

在上面的案例代码中,先执行访问无涯课堂的代码,后执行访问百度的代码,而且在访问百度代码的时候,刻意

加了等待2秒的时间,但是很遗憾的是访问无涯课堂的时候,网址不存在,导致堵塞,任务就立刻切换到访问百度,

执行完访问百度后,再任务切换到执行访问无涯课堂,以及任务结束。代码gevent.spawn()是创建一个协程任务,

遇到任务堵塞就切换,g1.join()是直到g1任务执行完成为止,见执行上面代码后,协程的任务切换,见执行结果截图:

当然有一种更加简单的方式来处理join,也就是说可以使用列表的方式来进行处理,修改代码的代码:

#!/usr/bin/env python
# -*-coding:utf-8 -*-


import  gevent
import  time as t
from gevent import  monkey
monkey.patch_all()
import  requests

def get_wuya():
    print('开始访问无涯课堂')
    r=requests.get('http://www.wuya.com')
    print(r.status_code)
    print('访问无涯课堂结束')

def get_baidu():
    print('开始访问百度')
    t.sleep(2)
    r=requests.get('http://www.baidu.com')
    print(r.status_code)
    print('访问百度结束')


g1=gevent.spawn(get_wuya)
g2=gevent.spawn(get_baidu)
gevent.joinall([g1,g2])

 

如果想在协程中实现对百度请求的并发请求,那么实现的源码为:

#!/usr/bin/env python
# -*-coding:utf-8 -*-


import  gevent
import  time as t
from gevent import  monkey
monkey.patch_all()
import  requests

def get_baidu():
    print('开始访问百度')
    r=requests.get('http://www.baidu.com')
    print(r.status_code)
    print('访问百度结束')


gevent_tasks=[]
for i in range(10):
    g1=gevent.spawn(get_baidu)
    gevent_tasks.append(g1)
gevent.joinall(gevent_tasks)

见执行代码后,执行的结果截图:

实现协程的思想来请求两个页面,一个堵塞了(可能是超时,可能是未知原因),就立刻切换到另外一个任务中执行,见实现的案例

代码:

#!/usr/bin/env python
# -*-coding:utf-8 -*-


import  gevent
import  time as t
from gevent import  monkey
monkey.patch_all()
import  requests

def get_sina():
    r=requests.get('http://www.sina.com')
    print('访问新浪结果:',r.status_code)

def get_baidu():
    r=requests.get('http://www.baidu.com')
    print('访问百度结果:',r.status_code)


gevent_tasks=[]
for i in range(100):
    g1=gevent.spawn(get_baidu)
    g2=gevent.spawn(get_sina)
    gevent_tasks.append(g1)
    gevent_tasks.append(g2)
gevent.joinall(gevent_tasks)

思想就是:最先访问百度,当访问百度堵塞,就立刻切换到访问新浪,如果访问新浪堵塞,也就立刻切换到访问百度,直到

任务执行结束,见执行过程的部分切换结果:

 

    

    

 

posted @ 2019-08-11 22:01  无涯(WuYa)  阅读(134)  评论(0编辑  收藏  举报