# 协程:
# 协程不是计算机提供的,是程序员认为创造的;也称之为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块相互切换执行。
# 主要意义:通过一个线程利用其IO等待事件去做一些其它事情。
# 实现协程的几种方式
# greenlet 早期的一个模块
# yield python关键字
# asyncio (py3.4)
# async、await python关键字(py3.5)
# 一、greenlet
# 安装
sudo apt-get install greenlet
# 例子:
from greenlet import greenlet
def func1():
print(1) # 第2步输出:1
gr2.switch()# 第3步切换到func2
print(2) # 第6步输出:2
gr2.switch()# 第7步切换到func2
def func2():
print(3) # 第4步输出:3
gr1.switch()# 第5步切换到func1
print(4) # 第8步输出:4
gr1 = greenlet(func1)
gr2 = greenlet(func2)
gr1.switch() # 第1步开始执行func1函数
# 二、yield关键字
def func1():
yield 1
yield from func2()
yield 2
def func2():
yield 3
yield 4
f1 = func1()
for item in f1:
print(item)
# 三、asyncio (py3.4及之后版本才自带)
import asyncio
@asyncio.coroutine
def func1():
print(1)
yield from asyncio.sleep(2) # 这里空闲的时候就会执行tasks中其他函数
print(2)
@asyncio.coroutine
def func2():
print(3)
yield from asyncio.sleep(2) # 这里空闲的时候就会执行tasks中其他函数
print(4)
tasks = [
asyncio.ensure_future( func1() ),
asyncio.ensure_future( func2() )
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
# 四、async & await关键字
import asyncio
async def func1():
print(1)
await asyncio.sleep(2) # 这里空闲的时候就会执行tasks中其他函数
print(2)
async def func2():
print(3)
await asyncio.sleep(2) # 这里空闲的时候就会执行tasks中其他函数
print(4)
tasks = [
asyncio.ensure_future( func1() ),
asyncio.ensure_future( func2() )
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
# 协程的一些概念
# async 关键字
# 协程函数:定义函数时候用 async def 前缀的函数叫协程函数
async def func():
pass
# 协程对象:执行协程函数得到的协程对象。
result = func() # 这里func返回的是协程对象,func函数中的代码并不会执行
# 协程函数不是直接调用的,携程函数需要执行的话需要用协程事件去执行
loop = asyncio.get_event_loop()
loop.run_until_complete(result)
asyncio.run( result ) # 这是python3.7及以后版本将上面两句简洁化了一下
# await 关键字
# await + 可等待对象(协程对象、Future、Task对象->io等待)
import asyncio
async def others(): # 定义协程函数
print('start')
await asyncio.sleep(2)
print('end')
return '返回值'
async def func(): # 定义协程函数
print('执行协程函数内部代码')
respose1 = await others() # 等待协程函数执行完成,然后打印返回值
print('io请求结束,结果为:'+ respose1)
respose2 = await others()
print('io请求结束,结果为:'+ respose2)
asyncio.run( func() )
# Task对象
# Task是继承Future
# 创建Task对象的方法:
# asyncio.create_task()
# loop.create_task()
# ensoure_future()
# 例1:传统方式使用Task
async def func():
print(1)
await asyncio.sleep(2)
print(2)
return '返回值'
async def main():
print('main开始')
# 创建Task对象,将当前执行的func函数任务添加到事件循环
task1 = asyncio.create_task( func() ) # 创建任务前必须先创建事件循环也就是调用asyncio.run
task2 = asyncio.create_task( func() ) # 创建的时候就自动将任务放进事件循环等待调度
print('task创建完成')
await asyncio.sleep(5)
ret1 = await task1 # 上一行休眠了五秒,在休眠期间task1执行完了的话就直接返回task1任务的执行结果,没有执行完就等待task1任务的执行结果
print('ret1')
ret2 = await task2
print('ret2')
print(ret1, ret2)
asyncio.run( main() )
# 例2:列表方式
import asyncio
async def func():
print(1)
await asyncio.sleep(2)
print(2)
return '返回值'
async def main():
print('main开始')
# task放到列表中
task_list = [
asyncio.create_task( func(), name='t1' ),
asyncio.create_task( func(), name='t2' ),
]
print('task创建完成')
done, pendding = await asyncio.wait(task_list, timeout=None) # done是执行后的返回值,pendding就是timeout超时后挂起(没执行完)的任务信息,一般timeout设置为None
print('done:',done)
print('pendding:',pendding)
asyncio.run( main() )
# 例3:协程对象列表
import asyncio
async def func():
print(1)
await asyncio.sleep(2)
print(2)
return '返回值'
task_list = [
func(),
func(),
]
done, pendding = asyncio.run( asyncio.wait( task_list ) ) # 这里的task_list不是Task对象而是协程对象,因为这个时候还没有创建事件循环,所以不能用Task对象
print('done:',done)
print('pendding:',pendding)
# asyncio.Future对象
# Task继承的Future,Task对象内容await结果的处理基于Future对象来的。
import asyncio
async def main():
loop = asyncio.get_running_loop() # 获取当前事件循环对象
fut = loop.create_future() # 创建一个任务(Future对象),这个任务什么都没干
await fut # 等待任务执行结果(future对象),没有结果会一直等下去。
asyncio.run( main() )
# 例2:
import asyncio
async def set_after(fut):
await asyncio.sleep(2)
fut.set_result('666')
async def main():
loop = asyncio.get_running_loop() # 获取当前事件循环对象
fut = loop.create_future()
await loop.create_task(set_after(fut))
data = await fut # Future对象
print(data)
asyncio.run( main() )
# 如果函数不支持await怎么处理
import concurrent.futures
import time
import asyncio
import threading
def func1():
print('func1 pid', threading.current_thread().ident)
time.sleep(3) # 某个耗时操作。如request.get方法不支持asyncio模式,所以只能用线程或进程去实现
return 'sa'
async def main():
print('main pid', threading.current_thread().ident)
# 写法一
loop = asyncio.get_running_loop()
fut = loop.run_in_executor(None, func1) # 将非协程函数,转换为协程Future对象。因为func1不是协程函数,所以没办法用await关键字去异步执行。run_in_executor方法是将func1放到线程池中去执行,然后将提交到线程池中的函数的返回值转换为asyncio.Future对象。所以func1实际上是开的另一个线程去执行的。
result = await fut
print('func1 result:', result)
# 线程模式
with concurrent.futures.ThreadPoolExecutor() as pool:
result = await loop.run_in_executor(pool, func1)
print('custom thread pool', result)
# 进程模式
with concurrent.futures.ProcessPoolExecutor() as pool:
result = await loop.run_in_executor(
pool, func1
)
print('costom prosess pool', result)
asyncio.run( main() )
# asyncio 异步迭代器
# 实现__aiter__() 和__anext__()方法对象。
import asyncio
class Reader(object):
def __init__(self):
self.count = 0
async def readLine(self):
self.count += 1
if self.count == 100:
return None
return self.count
def __aiter__(self):
return self
async def __anext__(self):
val = await self.readLine() # await 必须卸载async函数内
if val == None:
raise StopAsyncIteration
return val
async def func():
obj = Reader()
async for item in obj: # 异步迭代器for循环必须卸载协程函数内
print(item)
asyncio.run( func() )
# asyncio 异步上下文管理器
import asyncio
class AsyncContextManager:
def __init__(self, conn):
self.conn = conn
async def do_something(self):
return 666
async def __aenter__(self):
return self
async def __aexit__(self):
await asyncio.sleep(2)
async def func():
async with AsyncContextManager(None) as f: # async with必须在协程方法中
result = await f.do_something()
print(result)
asyncio.run(func())
# uvloop
# 是asyncio事件循环的替代方案。uvloop要比python自带的asyncio要快至少两倍。
# 安装:
sudo pip3 istall uvloop
# 如何将asyncio的事件循环替换成uvloop:
import asyncio
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) # 这里替换原来的事件循环机制
# ......其它代码不变