当前位置:首页>python>每日Python面试题 · 第3期

每日Python面试题 · 第3期

  • 2026-10-11 07:17:13
每日Python面试题 · 第3期
题目:下面代码执行需要多少秒?输出顺序是什么?
import asyncioasync def worker(i):    print(f"任务{i}开始")    await asyncio.sleep(1)    print(f"任务{i}结束")    return iasync def main():    tasks = [worker(i) for i in range(10)]    results = []    for task in tasks:        result = await task        results.append(result)    print(results)asyncio.run(main())

问题

  1. 这段代码是真正的并发执行吗?
  2. 程序总耗时大约是多少?
  3. 输出顺序是什么?
  4. 如何修改为真正的并发执行?
  5. 如果有 10000 个任务,同时 gather() 会有什么问题?

标准答案

第一问:不是并发执行

很多人第一眼看到:

tasks = [worker(i) for i in range(10)]

会以为创建了 10 个协程就开始并发了。

实际上这里只是生成了:

[    <coroutine object worker>,    <coroutine object worker>,    ...]

协程对象而已。


第二问:耗时约 10 秒

因为:

for task in tasks:    result = await task
等价于:
await worker(0)await worker(1)await worker(2)...
执行过程:
任务0开始等待1秒任务0结束任务1开始等待1秒任务1结束...

10个任务 × 1秒

总耗时:≈ 10 秒

第三问:输出顺序

严格按照顺序:

任务0开始任务0结束任务1开始任务1结束任务2开始任务2结束...任务9结束[0,1,2,3,4,5,6,7,8,9]

第四问:正确并发写法

使用:

results = await asyncio.gather(    *(worker(i) for i in range(10)))
或者:
tasks = [    asyncio.create_task(worker(i))    for i in range(10)]results = await asyncio.gather(*tasks)
此时:
任务0开始任务1开始任务2开始...任务9开始(等待1秒)任务0结束任务1结束...任务9结束
总耗时:≈ 1 秒
第五问:10000 个任务直接 gather 有什么风险?
await asyncio.gather(    *(worker(i) for i in range(10000)))

问题:

1. 内存暴涨

一次性创建:10000 个 Task

会占用大量内存。

2. 网络打爆

如果是:

aiohttp.get(...)

那么:10000个TCP连接

可能导致:

  • 本机端口耗尽
  • 服务端限流
  • Connection Reset
  • Too Many Requests

3. 事件循环压力巨大

事件循环需要维护:10000个Task状态

调度开销明显增加。

最佳实践:Semaphore 限流

例如最多同时执行 100 个:

import asynciosem = asyncio.Semaphore(100)async def worker(i):    async with sem:        await asyncio.sleep(1)        return iasync def main():    results = await asyncio.gather(        *(worker(i) for i in range(10000))    )asyncio.run(main())

面试官追问

asyncio.create_task() 和 await 的本质区别是什么?

优秀回答:

await coro()

表示:

立即执行,并等待结束。

而:

task = asyncio.create_task(coro())

表示:

把协程注册到事件循环,允许它与其他任务并发运行。

例如:

task1 = asyncio.create_task(fetch_user())task2 = asyncio.create_task(fetch_order())user = await task1order = await task2

总耗时:max(fetch_user, fetch_order)

而不是:fetch_user + fetch_order

一句话总结

创建协程 ≠ 执行协程;await 是排队干活,create_task() 才是真正把活扔进调度中心。 🚀

最新文章

随机文章