← 返回 Day 56 正文

Day 56 · 练习与清单

Day 056 — 异步编程(asyncio)练习清单

✅ 今日完成清单


📝 基础练习题

练习 1:异步计数器

编写一个异步函数 async_counter(n),每隔 0.5 秒打印一个数字,从 1 到 n。

python
import asyncio

async def async_counter(n):
    # 在这里编写代码
    pass

asyncio.run(async_counter(5))
# 预期输出:
# 1
# 2
# 3
# 4
# 5

练习 2:并发下载模拟

模拟并发下载 5 个文件,每个文件下载耗时不同(1-3 秒)。使用 asyncio.gather() 实现并发,并打印总耗时。

python
import asyncio
import time
import random

async def download_file(file_id):
    delay = random.randint(1, 3)
    print(f"开始下载文件 {file_id}...")
    await asyncio.sleep(delay)
    print(f"文件 {file_id} 下载完成! (耗时 {delay}s)")
    return f"file_{file_id}"

async def main():
    start = time.time()
    # 在这里使用 gather 并发下载
    # files = await asyncio.gather(...)
    elapsed = time.time() - start
    print(f"总耗时: {elapsed:.1f}s")

asyncio.run(main())

练习 3:错误处理

编写代码,使用 asyncio.gather() 同时运行 3 个协程,其中一个会抛出异常。使用 return_exceptions=True 收集所有结果,并区分成功和失败。

python
import asyncio

async def success_task():
    await asyncio.sleep(1)
    return "成功"

async def fail_task():
    await asyncio.sleep(0.5)
    raise ValueError("失败了")

async def main():
    # 在这里编写 gather 代码
    pass

asyncio.run(main())

🚀 进阶挑战题

挑战 1:异步生产者-消费者模型

使用 asyncio.Queue 实现一个生产者-消费者模型: - 生产者:每 0.5 秒产生一个数据项,共产生 10 个 - 消费者:3 个消费者并发消费,每个处理耗时 1 秒 - 打印每个数据项被哪个消费者处理

提示:使用 asyncio.create_task() 同时运行生产者和消费者。

挑战 2:异步超时重试装饰器

编写一个装饰器 @async_retry(max_retries=3, timeout=2.0),实现: - 自动重试失败的协程 - 每次重试使用指数退避(1s, 2s, 4s...) - 超过最大重试次数后抛出异常 - 支持超时控制

挑战 3:并发爬虫进度条

编写一个异步爬虫,支持: - 并发请求多个 URL - 实时显示进度(已完成/总数) - 支持暂停和恢复 - 使用 asyncio.Semaphore 限制并发数为 5


💡 参考答案提示

练习 1 提示
python
async def async_counter(n):
    for i in range(1, n + 1):
        print(i)
        await asyncio.sleep(0.5)
练习 2 提示
python
async def main():
    start = time.time()
    tasks = [download_file(i) for i in range(5)]
    files = await asyncio.gather(*tasks)
    elapsed = time.time() - start
    print(f"总耗时: {elapsed:.1f}s")  # 应该约 3 秒,不是 10 秒
练习 3 提示
python
async def main():
    results = await asyncio.gather(
        success_task(), fail_task(), success_task(),
        return_exceptions=True
    )
    for i, r in enumerate(results):
        if isinstance(r, Exception):
            print(f"任务 {i}: 失败 - {r}")
        else:
            print(f"任务 {i}: 成功 - {r}")

📚 推荐阅读