知道了多线程和进程,你可能不知道协程的存在
@Author: runsen
协程是实现并发编程的一种方式。https://docs.python.org/zh-cn/3/library/asyncio.html
一说并发,你肯定想到了多线程 , 多进程模型,没错,多线程 和 多进程,正是解决并发问题的经典模型之一
但是你了解过协程Coroutine吗?
协程:是单线程下的并发,又称微线程。
就是只有一个线程,如何提高速度,解决并发编程
英文名Coroutine。
协程比线程的单位更小——协程
注意协程这个概念完全是程序员自己想出来的东西,它对于操作系统来说根本不存在。操作系统只有进程和线程。
从一个demo学起
importtime
defprint_num(num):
print("Maoliisprinting"+str(num)+"nows")
time.sleep(1)
print("Maoliprints"+str(num)+"OK")
defmain(nums):
fornuminnums:
print_num(num)
%timemain([iforiinrange(1,6)])
Maoliisprinting1nows
Maoliprints1OK
Maoliisprinting2nows
Maoliprints2OK
Maoliisprinting3nows
Maoliprints3OK
Maoliisprinting4nows
Maoliprints4OK
Maoliisprinting5nows
Maoliprints5OK
Walltime:5s
%time 需要在jupyter notebook中运行。
上面代码是从上到下执行的。
下面将上面代码改为协程版
注意py版本3.7以上,主要使用的是asyncio
importasyncio
asyncdefprint_num(num):
print("Maoliisprinting"+str(num)+"nows")
awaitasyncio.sleep(1)
print("Maoliprints"+str(num)+"OK")
asyncdefmain(nums):
fornuminnums:
awaitprint_num(num)
%timeasyncio.run(main([iforiinrange(1,6)]))
Maoliisprinting1nows
Maoliprints1OK
Maoliisprinting2nows
Maoliprints2OK
Maoliisprinting3nows
Maoliprints3OK
Maoliisprinting4nows
Maoliprints4OK
Maoliisprinting5nows
Maoliprints5OK
Walltime:5.01s
asyncio.run() 函数用来运行最高层级的入口点 "main()" 函数
await 是同步调用等待一个协程。以下代码段会在等待 1 秒后打印 num,速度上没有发生改变。
需要引入asyncio.create_task才可以
可等待对象如果一个对象可以在 await 语句中使用,那么它就是 可等待 对象
协程中的还一个重要概念,任务(Task)
如果写一个数字是一个任务,那么毛利我要完成5个任务
毛利我写个1-5都这么慢,不行,我要加速写
asyncio.create_task() 函数用来并发运行作为 asyncio 任务 的多个协程。
importasyncio
asyncdefprint_num(num):
print("Maoliisprinting"+str(num)+"nows")
awaitasyncio.sleep(1)
print("Maoliprints"+str(num)+"OK")
asyncdefmain(nums):
tasks=[asyncio.create_task(print_num(num))fornuminnums]
fortaskintasks:
awaittask
%timeasyncio.run(main([iforiinrange(1,6)]))
Maoliisprinting1nows
Maoliisprinting2nows
Maoliisprinting3nows
Maoliisprinting4nows
Maoliisprinting5nows
Maoliprints1OK
Maoliprints3OK
Maoliprints5OK
Maoliprints2OK
Maoliprints4OK
Walltime:1.01s
还可以写成await asyncio.gather(*tasks)这种方法
importasyncio
asyncdefprint_num(num):
print("Maoliisprinting"+str(num)+"nows")
awaitasyncio.sleep(1)
print("Maoliprints"+str(num)+"OK")
asyncdefmain(nums):
tasks=[asyncio.create_task(print_num(num))fornuminnums]
awaitasyncio.gather(*tasks)
%timeasyncio.run(main([iforiinrange(1,6)]))
*tasks 解包列表,将列表变成了函数的参数;与之对应的是, ** dict 将字典变成了函数的参数。
#asyncio 队列
asyncio也是只有在Pytohn3.7才有的东西。
asyncio 队列被设计成与 queue 模块类似。
importasyncio
importrandom
asyncdefconsumer(queue,id):
whileTrue:
val=awaitqueue.get()
print('{}getaval:{}'.format(id,val))
awaitasyncio.sleep(1)
asyncdefproducer(queue,id):
foriinrange(5):
val=random.randint(1,10)
awaitqueue.put(val)
print('{}putaval:{}'.format(id,val))
awaitasyncio.sleep(1)
asyncdefmain():
#创建队列
queue=asyncio.Queue()
#消费者1号
consumer_1=asyncio.create_task(consumer(queue,'consumer_1'))
#消费者2号
consumer_2=asyncio.create_task(consumer(queue,'consumer_2'))
#生产者1号
producer_1=asyncio.create_task(producer(queue,'producer_1'))
#生产者2号
producer_2=asyncio.create_task(producer(queue,'producer_2'))
#stop10秒
awaitasyncio.sleep(10)
consumer_1.cancel()
consumer_2.cancel()
awaitasyncio.gather(consumer_1,consumer_2,producer_1,producer_2,return_exceptions=True)
%timeasyncio.run(main())
协程的写法简洁清晰,只要把 async / await 语法和 create_task 结合来用,就是Python中比较常见的协程
如果不会多线程,看我之前的文章。