处理Python异步IO之asyncio举例深度解析这类问题时,先确认目标场景,再按步骤核对配置或玩法细节。
异步编程是一种编程范式,它允许程序在等待某个操作完成时继续执行其他任务,而不是阻塞等待。在Python中,asyncio库是实现异步编程的核心。

在Python中,协程可以通过async def关键字定义:
import asyncioasync def hello(): print('Hello') await asyncio.sleep(1) print('World')# 运行协程asyncio.run(hello())事件循环是asyncio的核心,它负责调度协程的执行:
import asyncioasync def task1(): print('Task 1 started') await asyncio.sleep(2) print('Task 1 completed')async def task2(): print('Task 2 started') await asyncio.sleep(1) print('Task 2 completed')async def main(): # 创建任务 t1 = asyncio.create_task(task1()) t2 = asyncio.create_task(task2()) # 等待任务完成 await t1 await t2# 运行主协程asyncio.run(main())await关键字用于等待一个异步操作完成:
async def fetch_data(url): print(f'Fetching data from {url}') # 模拟网络请求 await asyncio.sleep(2) return f'Data from {url}'async def main(): # 串行执行 data1 = await fetch_data('https://api.example.com/data1') data2 = await fetch_data('https://api.example.com/data2') print(data1, data2)asyncio.run(main())asyncio.gather用于并发执行多个协程:
async def fetch_data(url): print(f'Fetching data from {url}') await asyncio.sleep(2) return f'Data from {url}'async def main(): # 并发执行 results = await asyncio.gather( fetch_data('https://api.example.com/data1'), fetch_data('https://api.example.com/data2'), fetch_data('https://api.example.com/data3') ) print(results)asyncio.run(main())asyncio.create_task用于创建后台任务:
async def background_task(): while True: print('Background task running') await asyncio.sleep(1)async def main(): # 创建后台任务 task = asyncio.create_task(background_task()) # 执行其他操作 print('Main task running') await asyncio.sleep(3) # 取消后台任务 task.cancel() try: await task except asyncio.CancelledError: print('Background task cancelled')asyncio.run(main())asyncio.wait用于等待多个协程完成:
async def task1(): await asyncio.sleep(2) return 'Task 1 result'async def task2(): await asyncio.sleep(1) return 'Task 2 result'async def main(): tasks = [task1(), task2()] done, pending = await asyncio.wait(tasks, timeout=1.5) print('Done tasks:', len(done)) print('Pending tasks:', len(pending)) for task in done: print('Result:', await task)asyncio.run(main())使用aiofiles库进行异步文件操作:
import asyncioimport aiofilesasync def read_file(filename): async with aiofiles.open(filename, 'r') as f: content = await f.read() return contentasync def write_file(filename, content): async with aiofiles.open(filename, 'w') as f: await f.write(content)async def main(): # 读取文件 content = await read_file('example.txt') print('File content:', content) # 写入文件 await write_file('output.txt', 'Hello, asyncio!') print('File written')asyncio.run(main())使用aiohttp库进行异步网络请求:
import asyncioimport aiohttpasync def fetch(session, url): async with session.get(url) as response: return await response.text()async def main(): async with aiohttp.ClientSession() as session: html = await fetch(session, 'https://example.com') print('HTML length:', len(html))asyncio.run(main())使用asyncpg库进行异步数据库操作:
import asyncioimport asyncpgasync def main(): # 连接数据库 conn = await asyncpg.connect( host='localhost', port=5432, user='postgres', password='password', database='mydb' ) # 执行查询 rows = await conn.fetch('SELECT * FROM users') for row in rows: print(row) # 关闭连接 await conn.close()asyncio.run(main())使用async with语句创建异步上下文管理器:
import asyncioclass AsyncContextManager: async def __aenter__(self): print('Entering context') await asyncio.sleep(1) return self async def __aexit__(self, exc_type, exc_val, exc_tb): print('Exiting context') await asyncio.sleep(1)async def main(): async with AsyncContextManager() as cm: print('Inside context') await asyncio.sleep(2)asyncio.run(main())使用async for语句创建异步迭代器:
import asyncioclass AsyncIterator: def __init__(self, start, end): self.start = start self.end = end def __aiter__(self): self.current = self.start return self async def __anext__(self): if self.current >= self.end: raise StopAsyncIteration value = self.current self.current += 1 await asyncio.sleep(0.5) return valueasync def main(): async for num in AsyncIterator(1, 5): print(num)asyncio.run(main())
Python 3.11+引入了任务组,用于更安全地管理并发任务:
import asyncioasync def task(id, duration): print(f'Task {id} started') await asyncio.sleep(duration) print(f'Task {id} completed') return f'Task {id} result'async def main(): async with asyncio.TaskGroup() as tg: # 创建任务 task1 = tg.create_task(task(1, 2)) task2 = tg.create_task(task(2, 1)) task3 = tg.create_task(task(3, 3)) # 任务组退出时,所有任务已完成 print('All tasks completed') print('Task 1 result:', task1.result()) print('Task 2 result:', task2.result()) print('Task 3 result:', task3.result())asyncio.run(main())在异步代码中避免使用阻塞操作,如同步IO:
# 错误示例async def bad_example(): # 阻塞操作 time.sleep(1) # 这会阻塞整个事件循环 print('Done')# 正确示例async def good_example(): # 异步操作 await asyncio.sleep(1) # 这会释放事件循环 print('Done')对于多个IO操作,使用并发执行:
async def fetch_all(urls): async with aiohttp.ClientSession() as session: tasks = [fetch(session, url) for url in urls] results = await asyncio.gather(*tasks) return results
为异步操作设置超时:
async def fetch_with_timeout(url, timeout=5): try: async with aiohttp.ClientSession() as session: async with asyncio.timeout(timeout): async with session.get(url) as response: return await response.text() except asyncio.TimeoutError: return 'Request timed out'
忘记使用await会导致协程不会执行:
async def foo(): print('Foo') await asyncio.sleep(1) print('Bar')async def main(): foo() # 错误:忘记await,协程不会执行 await foo() # 正确:使用awaitasyncio.run(main())在协程中使用阻塞操作会阻塞整个事件循环:
async def blocking_operation(): # 错误:使用阻塞操作 time.sleep(1) # 这会阻塞事件循环 return 'Done'async def main(): # 正确:使用线程池执行阻塞操作 loop = asyncio.get_event_loop() result = await loop.run_in_executor(None, lambda: time.sleep(1)) return result
创建的任务如果不等待或取消,会导致任务泄漏:
async def background_task(): while True: await asyncio.sleep(1) print('Background task')async def main(): # 错误:创建任务但不管理 asyncio.create_task(background_task()) await asyncio.sleep(5) # 任务会继续运行,导致泄漏async def main_fixed(): # 正确:管理任务生命周期 task = asyncio.create_task(background_task()) await asyncio.sleep(5) task.cancel() try: await task except asyncio.CancelledError: pass使用aiohttp创建异步Web服务器:
from aiohttp import webasync def handle(request): name = request.match_info.get('name', 'World') # 模拟异步操作 await asyncio.sleep(0.5) return web.Response(text=f'Hello, {name}!')async def main(): app = web.Application() app.add_routes([ web.get('/', handle), web.get('/{name}', handle) ]) runner = web.AppRunner(app) await runner.setup() site = web.TCPSite(runner, 'localhost', 8080) await site.start() print('Server started on http://localhost:8080') # 保持运行 await asyncio.Future() # 无限等待if __name__ == '__main__': asyncio.run(main())使用aiohttp创建异步爬虫:
import asyncioimport aiohttpfrom bs4 import BeautifulSoupasync def fetch_url(session, url): try: async with session.get(url) as response: return await response.text() except Exception as e: print(f'Error fetching {url}: {e}') return ''async def parse_page(html): soup = BeautifulSoup(html, 'html.parser') links = [] for a in soup.find_all('a', href=True): links.append(a['href']) return linksasync def crawl(start_url, max_depth=2): visited = set() queue = [(start_url, 0)] async with aiohttp.ClientSession() as session: while queue: url, depth = queue.pop(0) if url in visited or depth >= max_depth: continue visited.add(url) print(f'Crawling {url} (depth: {depth})') html = await fetch_url(session, url) if not html: continue links = await parse_page(html) for link in links: if link.startswith('http'): queue.append((link, depth + 1))async def main(): await crawl('https://example.com')asyncio.run(main())使用asyncpg进行异步数据库操作:
import asyncioimport asyncpgasync def setup_database(): # 连接数据库 conn = await asyncpg.connect( host='localhost', port=5432, user='postgres', password='password', database='mydb' ) # 创建表 await conn.execute(''' CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(100), email VARCHAR(100) UNIQUE ) ''') # 插入数据 await conn.execute( 'INSERT INTO users (name, email) VALUES ($1, $2) ON CONFLICT DO NOTHING', 'Alice', '[email protected]' ) await conn.execute( 'INSERT INTO users (name, email) VALUES ($1, $2) ON CONFLICT DO NOTHING', 'Bob', '[email protected]' ) # 查询数据 rows = await conn.fetch('SELECT * FROM users') print('Users:') for row in rows: print(f'ID: {row["id"]}, Name: {row["name"]}, Email: {row["email"]}') # 关闭连接 await conn.close()asyncio.run(setup_database())asyncio为Python带来了强大的异步编程能力,使得我们可以编写高效的I/O密集型应用。通过合理使用asyncio的各种特性,我们可以:
通过掌握asyncio,我们可以构建高性能、可扩展的Python应用,特别是在处理大量I/O操作的场景中,如Web服务器、爬虫、数据处理等。