在 Python 中,asyncio.gather()
是 asyncio
模块提供的一个关键函数,用于并发运行多个异步任务(协程)并收集它们的返回值。它是异步编程中常用的工具,适合需要同时执行多个独立 I/O 操作(如网络请求、文件读写)的场景。asyncio.gather()
提高了代码效率,同时保持异步事件循环的非阻塞特性。
以下是对 asyncio.gather()
的详细介绍,包括其定义、用法、示例、应用场景、最佳实践和注意事项。内容基于 Python 官方文档(Python 3.9+)和实际使用经验。
asyncio.gather()
的定义和原理asyncio.gather(*aws, return_exceptions=False)
是一个异步函数,用于并发运行多个可等待对象(awaitable objects,如协程、任务或 Future),并在所有任务完成后返回它们的执行结果。
参数:
*aws
:可变数量的可等待对象(通常是协程或 asyncio.Task
)。return_exceptions
:布尔值,控制异常处理方式:
False
(默认):任意任务抛出异常,整个 gather
立即失败,抛出该异常。True
:异常作为结果返回,不中断其他任务。返回值:一个 list
,按输入顺序包含每个可等待对象的结果(或异常对象,如果 return_exceptions=True
)。
asyncio.gather()
将所有可等待对象调度到事件循环,允许它们并发运行(基于事件循环的非阻塞机制)。return_exceptions
参数,决定是否将异常作为结果返回或抛出。asyncio.wait()
:更低级,返回完成和未完成任务的集合,灵活但复杂。asyncio.as_completed()
:按完成顺序迭代结果,适合处理实时结果。asyncio.gather()
:简单、高效,适合需要所有结果的场景。asyncio.gather()
的基本用法import asyncio
async def my_coroutine():
return 42
async def main():
results = await asyncio.gather(my_coroutine(), my_coroutine())
print(results) # 输出: [42, 42]
asyncio.run(main())
asyncio.gather()
常用于并发执行多个耗时任务(如网络请求)。
示例:
import asyncio
async def task(name, delay):
await asyncio.sleep(delay)
return f"{name} completed after {delay}s"
async def main():
tasks = [
task("A", 2),
task("B", 1),
task("C", 3)
]
results = await asyncio.gather(*tasks)
print(results)
asyncio.run(main())
输出:
['A completed after 2s', 'B completed after 1s', 'C completed after 3s']
设置 return_exceptions=True
捕获异常。
示例:
import asyncio
async def success():
await asyncio.sleep(1)
return "Success"
async def fail():
await asyncio.sleep(0.5)
raise ValueError("Failed")
async def main():
results = await asyncio.gather(success(), fail(), return_exceptions=True)
print(results)
asyncio.run(main())
输出:
['Success', ValueError('Failed')]
asyncio.create_task
将协程包装为任务,提前调度。
示例:
import asyncio
async def task(name):
await asyncio.sleep(1)
return name
async def main():
tasks = [asyncio.create_task(task(name)) for name in ["A", "B"]]
results = await asyncio.gather(*tasks)
print(results)
asyncio.run(main())
输出:
['A', 'B']
asyncio.gather()
的核心特性gather
调度所有任务并发运行,利用事件循环的非阻塞特性。return_exceptions=False
):任意任务失败,gather
抛出异常,未完成任务继续运行但结果不可用。return_exceptions=True
:所有任务完成,异常作为结果返回。gather
被取消(通过 Task.cancel()
),所有子任务会被取消。示例:
import asyncio
async def task(name):
await asyncio.sleep(10)
return name
async def main():
tasks = [task(name) for name in ["A", "B"]]
try:
await asyncio.wait_for(asyncio.gather(*tasks), timeout=1)
except asyncio.TimeoutError:
print("Timed out")
asyncio.run(main())
输出:
Timed out
并发发送多个 HTTP 请求(如爬虫、API 调用)。
示例(结合 aiohttp
):
import asyncio
import aiohttp
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
urls = ["https://example.com"] * 3
results = await asyncio.gather(*(fetch(url) for url in urls))
print(f"Fetched {len(results)} pages")
asyncio.run(main())
并发执行数据库查询。
示例(结合 aiosqlite
):
import asyncio
import aiosqlite
async def query(db_name, id):
async with aiosqlite.connect(db_name) as db:
async with db.execute("SELECT ? AS id", (id,)) as cursor:
return await cursor.fetchone()
async def main():
tasks = [query(":memory:", i) for i in range(3)]
results = await asyncio.gather(*tasks)
print(results) # 输出: [(0,), (1,), (2,)]
asyncio.run(main())
asyncio.Semaphore
限制并发任务数量。
示例:
import asyncio
async def task(name, semaphore):
async with semaphore:
await asyncio.sleep(1)
return name
async def main():
semaphore = asyncio.Semaphore(2) # 限制 2 个并发
tasks = [task(str(i), semaphore) for i in range(5)]
results = await asyncio.gather(*tasks)
print(results)
asyncio.run(main())
并发处理多个独立任务(如文件处理)。
示例:
import asyncio
async def process_file(filename):
await asyncio.sleep(1) # 模拟处理
return f"Processed {filename}"
async def main():
files = ["file1.txt", "file2.txt", "file3.txt"]
results = await asyncio.gather(*(process_file(f) for f in files))
print(results)
asyncio.run(main())
使用 return_exceptions=True
处理异常:
results = await asyncio.gather(*tasks, return_exceptions=True)
for result in results:
if isinstance(result, Exception):
print(f"Error: {result}")
else:
print(result)
结合 asyncio.create_task
:
tasks = [asyncio.create_task(coro) for coro in coroutines]
await asyncio.gather(*tasks)
限制并发:
asyncio.Semaphore
避免资源过载。semaphore = asyncio.Semaphore(5)
async def limited_task():
async with semaphore:
await do_work()
异常和日志:
import logging
logging.basicConfig(level=logging.INFO)
async def main():
try:
await asyncio.gather(*tasks)
except Exception as e:
logging.error(f"Error: {e}")
测试异步代码:
pytest
和 pytest-asyncio
测试 gather
行为。import pytest
import asyncio
@pytest.mark.asyncio
async def test_gather():
async def task():
return 42
results = await asyncio.gather(task(), task())
assert results == [42, 42]
版本要求:
asyncio.gather()
需要 Python 3.5+。import sys
assert sys.version_info >= (3, 5), "Requires Python 3.5+"
异常传播:
gather
,需设置 return_exceptions=True
或捕获异常。try:
await asyncio.gather(fail(), success())
except ValueError:
print("Caught error")
任务取消:
gather
被取消,所有子任务也会被取消。task = asyncio.create_task(asyncio.gather(*tasks))
task.cancel()
性能优化:
gather
适合 I/O 密集型任务,CPU 密集型任务应使用 multiprocessing
。from multiprocessing import Pool
调试并发:
asyncio.all_tasks()
或日志检查任务状态。print(asyncio.all_tasks())
asyncio.gather()
是 Python 异步编程中用于并发运行多个协程并收集结果的强大工具。其核心特点包括:
await asyncio.gather(*coroutines)
运行任务。结合 asyncio.Semaphore
等工具,gather
可以高效管理异步并发。
参考文献: