1.在python3.4之前,协程是通过生成器(yield)实现的:
def count_down(n):
while n > 0:
yield n
n -= 1
if __name__ == '__main__':
rest = count_down(5)
print(next(rest))
print(next(rest))
print(next(rest))
print(next(rest))
print(next(rest))
控制台输出:
5
4
3
2
1
或者将yield当成是一个赋值语句,实现协程的函数
def test_yield():
while True:
n = (yield)
print(n)
if __name__ == '__main__':
rest = test_yield()
next(rest)
rest.send('666')
rest.send('666')
控制台输出:
666
666
2.python3.4之后,使用async和await关键字实现
使用async定义特殊的函数,当被调用时,不执行里面的代码,而是返回一个协程对象,在事件循环中调用执行代码前,协程对象不执行任何操作,因此,要先定义一个事件循环队列,并注册任务,即添加进事件队列,然后等待队列前面的任务执行结束,调用该任务,执行
当遇到阻塞调用的函数时,用await函数将协程的控制权让出,队列先调用其他的任务
import asyncio
async def do_sth(x):
print('等待中:{0}'.format(x))
await asyncio.sleep(x)
print(asyncio.iscoroutinefunction(do_sth))
coroutine = do_sth(5)
# 事件循环队列
loop = asyncio.get_event_loop()
# 注册任务
task = loop.create_task(coroutine)
print(task)
#执行直到结束
loop.run_until_complete(task)
print(task)
控制台输出:
True # 是协程函数
<Task pending coro=<do_sth() running at D:/untitled/test_xiecheng/test.py:4>>
等待中:5
<Task finished coro=<do_sth() done, defined at D:/untitled/test_xiecheng/test.py:4> result=None>
3.协程通信之嵌套调用:
一个协程的执行过程,依赖于另一个协程函数的返回
import asyncio
async def comput(x, y):
print('正在计算x+y==>{0}+{1}'.format(x,y))
await asyncio.sleep(2) # asyncio的sleep返回的是一个协程对象
return x+y
async def get_sum(x,y):
rest = await comput(x,y)
# rest = comput(x,y)
# 假设comput是一个相对任务(用asyncio模块中的sleep来模拟),
# 等待comput函数执行结束之后要得到结果。用上await即可
print('{0}+{1}={2}'.format(x, y, rest))
loop = asyncio.get_event_loop()
loop.run_until_complete(get_sum(1, 2))
loop.close()
4.协程通信之队列
import asyncio
import random
async def add(q,name):
for i in range(10):
await asyncio.sleep(random.randint(1,3))
await q.put(i)
print('add:{0},q.size:{1}'.format(name,q.qsize()))
async def reduce(q,name):
while True:
await asyncio.sleep(random.randint(1, 5))
await q.get()
print('reduce:{0},q.size:{1}'.format(name,q.qsize()))
q = asyncio.Queue(maxsize=5)
a1 = add(q,'a1')
r = reduce(q,'r')
# 事件循环队列
loop = asyncio.get_event_loop()
# 注册任务
#执行直到结束
loop.run_until_complete(asyncio.gather(a1,r))
loop.close()
控制台部分输出:
add:a1,q.size:1
add:a1,q.size:2
reduce:r,q.size:1
add:a1,q.size:2
reduce:r,q.size:1
此时由于get相关代码等待的时间比put长一些,所以会存在add多个,才有一个get的操作