协程

协程

1、greenlet+switch

采用greenlet+switch机制来实现协程
greenlet用于创建协程,switch进行协程之间的切换

某个协程在执行的过程中可以随时被其他协程通过switch来打断,转而去执行其他协程,当前的中
现场会被保留,一旦中断的协程再次获得cpu会恢复现场然后从中断处继续执行
这种机制下的协程是串行的,不能并发

举些例子说明一下

采用greenlet+switch机制来实现协程,这种机制下的协程是串行的,不能并发
_ey1.py

from greenlet import greenlet
from time import sleep

def func1():
    print("协程1")
    

def func2():
    print("协程2")
    

def func3():
    print("协程3")
   

if __name__ == '__main__':
    # 使用greenlet创建三个协程
    g1 = greenlet(func1)
    g2 = greenlet(func2)
    g3 = greenlet(func3)
    print(g1)
    # 开启协程
    g1.switch() # 将cpu的使用权转移给g1

运行这个程序,开启的是协程1

<greenlet.greenlet object at 0x0000022AA2CD1898>
协程1

在程序尾部g1.switch()后加入一行

g2.switch()

让函数func1运行后睡3秒

def func1():
    print("协程1")
    sleep(3)

然后运行这个程序,发现打印协程1,过3秒后打印协程2,如果是并发,协程1和协程2应同时打印,说明这种机制下的协程是串行的,不能并发

协程1
协程2

_ey2 .py

from greenlet import greenlet
from time import sleep

def func1():
    print("协程1")
    sleep(2)
    g2.switch()  # 在这里协程1发生了中断,转而执行协程2,此时协程1的线程会被cpu保存,一旦协程1再次获得cpu的执行权,就会立即恢复现场然后从端点处继续往下执行
    print("协程1恢复执行!")

def func2():
    print("协程2")
    sleep(4)
    g3.switch()
    print("协程2恢复执行!")

def func3():
    print("协程3")
    sleep(8)
    g1.switch()

if __name__ == '__main__':
    # 使用greenlet创建三个协程
    g1 = greenlet(func1)
    g2 = greenlet(func2)
    g3 = greenlet(func3)
    # print(g1)
    
    # 开启协程
    g1.switch() # 将cpu的使用权转移给g1

看一下打印的结果

协程1
协程2
协程3
协程1恢复执行!

这里执行的顺序为:
线程1开启 (打印协程1) --> 2秒后开启线程2 (打印协程2) --> 4秒后开启协程3 (打印协程3) --> 8秒后开启协程1,但是是从断点出执行 (打印协程1恢复执行)

2、gevent

_ey3 .py

import gevent
from time import sleep

def func1():
    print("协程1")
    sleep(2)

def func2():
    print("协程2")
    sleep(4)
    
def func3():
    print("协程3")

if __name__ == '__main__':
    # 用gevent来创建三个协程
    g1 = gevent.spawn(func1)
    g2 = gevent.spawn(func2)
    g3 = gevent.spawn(func3)
    # print(g1)

    # 将三个协程加入到协程队列中执行
    gevent.joinall([g1,g2,g3]) # 这个队列是一个同步对列,三个协程只能串行执行

运行这个程序,先打印协程1,过2秒后打印协程2,过4秒后打印协程3,所以这三个协程也是串行执行

3、gevent + monkey

协程创建出来执行的时候默认是多个协程同步(串行)
使用monkey可以将协程的同步机制转成异步机制

先看一个程序
_ey4 .py

import requests
import gevent

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}

def func(url,i):
    print("协程%d开启"%i)
    res = requests.get(url,headers=headers)
    html = res.text
    print("协程%d执行结束,获取到的响应体的大小为:%d"%(i,len(html)))

if __name__ == '__main__':
    urls = [
        "https://www.baidu.com/",
        "https://www.163.com/",
        "https://www.qq.com/",
        "https://www.sina.com.cn/",
        "https://www.ifeng.com/"
    ]
    # 创建5个协程用于访问5个网站
    g_list = []
    for i in range(len(urls)):
        g = gevent.spawn(func,urls[i],i) # spawn参数分别代表,第一个参数协程的绑定的函数,后面的参数都是函数的参数
        g_list.append(g)

    # 将5个协程加入到队列中
    gevent.joinall(g_list)

查看打印结果,这些都是按顺序执行的,一个协程开启,第二个协程要开启,只有等第一个协程结束后才能开启

协程0开启
协程0执行结束,获取到的响应体的大小为:156399
协程1开启
协程1执行结束,获取到的响应体的大小为:680096
协程2开启
协程2执行结束,获取到的响应体的大小为:228548
协程3开启
协程3执行结束,获取到的响应体的大小为:579635
协程4开启
协程4执行结束,获取到的响应体的大小为:216010

现在,修改一下,使用monkey,这5个线程一起执行,变成了异步

import requests
import gevent
from gevent import monkey
# 用monkey给整个协程队列添加一个非阻塞I/O操作,使其成为一个异步(并发或者并行)的队列
monkey.patch_all()

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36'}

def func(url,i):
    print("协程%d开启"%i)
    res = requests.get(url,headers=headers)
    html = res.text
    print("协程%d执行结束,获取到的响应体的大小为:%d"%(i,len(html)))

if __name__ == '__main__':
    urls = [
        "https://www.baidu.com/",
        "https://www.163.com/",
        "https://www.qq.com/",
        "https://www.sina.com.cn/",
        "https://www.ifeng.com/"
    ]
    # 创建5个协程用于访问5个网站
    g_list = []
    for i in range(len(urls)):
        g = gevent.spawn(func,urls[i],i) # spawn参数分别代表,第一个参数协程的绑定的函数,后面的参数都是函数的参数
        g_list.append(g)

    # 将5个协程加入到队列中
    gevent.joinall(g_list)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值