threading模块通过应用线程实现并发,multiprocessing使用进程实现并发。在python中,还有另外一种实现并发的方式,那就是协程——一种单线程单进程的方法来实现并发,通过asyncio模块可以实现。
使用asyncio并发执行任务有五种方式,分别是:
- gather: 返回结果的顺序与传参顺序一致
- wait:返回结果是一个元组,包含两个集合,已完成的任务和未完成的任务,支持timeout参数和return_when参数
- create_task:创建的task可以通过cancel方法取消
- ensure_future:在使用await之前,协程不会启动
- as_completed: 创建生成器管理一个协程列表并生成他们的结果
下面将分别提供demo举例说明,假设我们要并发执行的任务如下:
模拟一个创建服务器连接的任务
import asyncio
async def get_connection(name):
"""模拟创建连接"""
print(f'正在创建连接: {name} ...')
await asyncio.sleep(1) # 假设连接过程需要1秒,注意这里不能用time.sleep(),因为它不是异步函数
print(f'{name} 创建成功!')
return name
方式一:gather
async def coroutine1(count):
"""count: 并行任务的数量"""
start = time.perf_counter()
tasks = []
for i in range(count):
tasks.append(get_connection(f'conn{i}'))
result = await asyncio.gather(*tasks)
print('耗时', time.perf_counter() - start)
return True
运行
if __name__ == '__main__':
coro = coroutine1(5)
values = asyncio.run(coro)
print(values)
结果:
正在创建连接: conn0 ...
正在创建连接: conn1 ...
正在创建连接: conn2 ...
正在创建连接: conn3 ...
正在创建连接: conn4 ...
conn0 创建成功!
conn2 创建成功!
conn4 创建成功!
conn1 创建成功!
conn3 创建成功!
耗时 1.0077441999999999
['conn0', 'conn1', 'conn2', 'conn3', 'conn4']
方式二:wait
async def coroutine2(count):
start = time.perf_counter()
tasks = []
for i in range(count):
tasks.append(get_connection(f'conn{i}'))
result = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
print('耗时', time.perf_counter() - start)
return result
运行方式同方式一,不再赘述
结果:
({<Task finished coro=<get_connection() done, defined at D:/PythonProjects/learnasyncio/learn_asyncio.py:69> result=True>, <Task finished coro=<get_connection() done, defined at D:/PythonProjects/learnasyncio/learn_asyncio.py:69> result=True>, <Task finished coro=<get_connection() done, defined at D:/PythonProjects/learnasyncio/learn_asyncio.py:69> result=True>, <Task finished coro=<get_connection() done, defined at D:/PythonProjects/learnasyncio/learn_asyncio.py:69> result=True>, <Task finished coro=<get_connection() done, defined at D:/PythonProjects/learnasyncio/learn_asyncio.py:69> result=True>}, set())
方式三:create_task
async def coroutine3(count):
start = time.perf_counter()
tasks = []
for i in range(count):
tasks.append(asyncio.create_task(get_connection(f'conn{i}')))
for task in tasks:
await task
result = [task.result() for task in tasks]
print('耗时', time.perf_counter() - start)
return result
方式四:ensure_future
async def coroutine4(count):
start = time.perf_counter()
tasks = []
for i in range(count):
tasks.append(asyncio.ensure_future(get_connection(f'conn{i}')))
for task in tasks:
await task
result = [task.result() for task in tasks]
print('耗时', time.perf_counter() - start)
return result
方式五:as_completed
async def coroutine5(count):
tasks = [
get_connection(f'conn{i}')
for i in range(count)
]
start = time.perf_counter()
results = []
for next_to_complete in asyncio.as_completed(tasks):
result = await next_to_complete
results.append(result)
print('耗时', time.perf_counter() - start)
return results