python-协程二(创建协程)

一、协程在python中常用的包

  yieldgreenletgeventasyncio

 

二、创建协程

  1)使用yield创建协程

import time


def consumer(name):  # 生成器
    print("%s 要开始吃包子了!" % name)
    while True:
        baozi=yield    # 暂停,记录位置,返回跳出(接收下面send发送的数据,接收到数据后才会继续执行)
        print("包子%s,%s吃了"%(baozi,name))


def producer(name):
    c = consumer("消费者")   # 只是变成一个生成器
    c.__next__()       # next只唤醒yield不传递值
    for i in range(4):
        time.sleep(1)
        print("%s 做了包子%s"%(name,i))
        c.send(i)  # 发送数据


if __name__ == "__main__":
    producer("生产者")

结果:
消费者 要开始吃包子了!
生产者 做了包子0
包子0,消费者吃了
生产者 做了包子1
包子1,消费者吃了
生产者 做了包子2
包子2,消费者吃了
生产者 做了包子3
包子3,消费者吃了

  2)使用greenlet创建协程

from greenlet import greenlet


def proc1():
    print(12)
    gr2.switch()  # 执行权切换到gr2,gr1暂停执行
    print(34)
    gr2.switch()  # 执行权切换到gr2,gr1将从刚才暂停的地方继续执行


def proc2():
    print(56)
    gr1.switch()  # 执行权切换到gr1,gr1将从刚才暂停的地方继续执行,gr2暂停执行
    print(78)


if __name__ == "__main__":
    gr1 = greenlet(proc1)  # 启动协程1
    gr2 = greenlet(proc2)  # 启动协程2
    gr1.switch()  # 先执行gr1指定运行的函数

结果:
12
56
34
78

  3)使用gevent创建协程

from gevent import monkey; monkey.patch_all()  # 这个代表遇到IO就移交执行权,不用等待
import gevent
import requests


def f(url):
    print('GET: %s' % url)
    resp = requests.get(url)  # 网络IO会切换执行权
    data = resp.text
    print('%d bytes received from %s.' % (len(data), url))


gevent.joinall([
        gevent.spawn(f, 'https://www.baidu.com/'),
        gevent.spawn(f, 'https://www.sina.com.cn/'),
        gevent.spawn(f, 'https://sohu.com/'),
])

结果:
GET: https://www.baidu.com/
GET: https://www.sina.com.cn/
GET: https://sohu.com/
537854 bytes received from https://www.sina.com.cn/.
2443 bytes received from https://www.baidu.com/.
177385 bytes received from https://sohu.com/.
结论:当遇到IO的时候,就切换执行权了,去执行其他任务,然后等网络IO写回来再继续往下执行
import gevent import requests def f(url): print('GET: %s' % url) resp = requests.get(url) # 网络IO会切换执行权 data = resp.text print('%d bytes received from %s.' % (len(data), url)) gevent.joinall([ gevent.spawn(f, 'https://www.baidu.com/'), gevent.spawn(f, 'https://www.sina.com.cn/'), gevent.spawn(f, 'https://sohu.com/'), ]) 结果: GET: https://www.baidu.com/ 2443 bytes received from https://www.baidu.com/. GET: https://www.sina.com.cn/ 537846 bytes received from https://www.sina.com.cn/. GET: https://sohu.com/ 177385 bytes received from https://sohu.com/. 结论:如果没有monkey.patch_all(),那么协程会一个一个任务的执行,当遇到IO的时候,它也会等待内容返回,再去执行下一个任务

  3)使用asyncio创建协程

import time
import asyncio

'''
单协程实例
'''

now = time.time()  # 返回当前时间戳


async def do_some_work(x):  # 定义协程任务,前缀必须要写async
    print('Waiting: ', x)
    time.sleep(x)

if __name__ == "__main__":
    start = time.time()
    coroutine1 = do_some_work(2)  # 把协程任务的对象存放到变量里
    coroutine2 = do_some_work(3)
    loop = asyncio.get_event_loop()  # 创建一个事件循环
    loop.run_until_complete(coroutine1)  # 把协程注册到事件循环,并启动事件循环
    loop.run_until_complete(coroutine2)  # 把协程注册到事件循环,并启动事件循环
    print('TIME: ', time.time() - start)

结果:
Waiting:  2
Waiting:  3
TIME:  5.001837491989136
import time
import asyncio

'''
绑定回调
'''


async def do_some_work(x):  # 协程任务,前缀async
    print('Waiting: ', x)
    return 'Done after {}s'.format(x)


def callback(a):  # a 代表协程任务的对象
    print('Callback: ', a.result())  # a.result() 固定写法,获取协程任务的返回值。


if __name__ == "__main__":
    start = time.time()
    coroutine = do_some_work(2)  # 把协程任务的对象存放到变量里
    loop = asyncio.get_event_loop()  # 把协程注册到事件循环,并启动事件循环
    task = asyncio.ensure_future(coroutine)  # 创建一个task
    task.add_done_callback(callback)  # 绑定回调
    loop.run_until_complete(task)  # 把test注册到事件循环,并启动事件循环
    print('TIME: ', time.time() - start)

结果:

Waiting: 2
Callback: Done after 2s
TIME: 0.0009970664978027344

猜你喜欢

转载自www.cnblogs.com/su-sir/p/12590231.html