You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在asyncio程序中使用time.sleep()的问题及替代方案咨询

解决asyncio中阻塞操作(time.sleep)导致的事件循环卡顿问题

你的核心问题是asyncio事件循环被阻塞操作(如time.sleep)卡住——time.sleep会占用事件循环所在线程,完全阻止其他异步任务执行。之前用create_task和gather没用,是因为这些方法仅负责调度异步任务,但任务内部的阻塞代码仍会垄断线程资源。

下面分两种场景给出解决方案:

场景1:可以修改含time.sleep的函数

如果能控制阻塞代码(比如你自己写的test_loop),直接把time.sleep()替换成await asyncio.sleep(),这是最贴合asyncio设计的方案:

import asyncio

async def test_loop():
    loop_counter = 0
    while True:
        print('loop')
        # 替换time.sleep为asyncio.sleep,主动让出事件循环控制权
        await asyncio.sleep(2)
        if loop_counter >= 5:
            break
        loop_counter += 1

async def delay_msgs():
    print('run msgs')
    await asyncio.sleep(5)
    print('asdf')
    await asyncio.sleep(10)
    print("qwerty")

async def main():
    task1 = asyncio.create_task(delay_msgs())
    task2 = asyncio.create_task(test_loop())
    await asyncio.gather(task1, task2)

if __name__ == '__main__':
    asyncio.run(main())

修改后两个任务会真正并发执行:test_loop每2秒打印一次,delay_msgs会在5秒后正常输出asdf,不会被test_loop的sleep操作卡住。

场景2:无法修改阻塞函数(如第三方库的openai.ChatCompletion.create)

如果阻塞代码是第三方库(比如openai的方法内部使用了time.sleep),无法直接修改,就把这个阻塞操作放到线程池里执行,让事件循环线程不被占用。

方案A:用asyncio.to_thread()(Python 3.9+)

这是最简单的实现方式,直接把阻塞函数包装在to_thread中:

import asyncio
import time

# 模拟无法修改的阻塞函数(对应openai.ChatCompletion.create)
def blocking_test_loop():
    loop_counter = 0
    while True:
        print('loop')
        time.sleep(2)
        if loop_counter >= 5:
            break
        loop_counter += 1

async def test_loop():
    # 将阻塞函数放到线程池执行
    await asyncio.to_thread(blocking_test_loop)

async def delay_msgs():
    print('run msgs')
    await asyncio.sleep(5)
    print('asdf')
    await asyncio.sleep(10)
    print("qwerty")

async def main():
    task1 = asyncio.create_task(delay_msgs())
    task2 = asyncio.create_task(test_loop())
    await asyncio.gather(task1, task2)

if __name__ == '__main__':
    asyncio.run(main())

方案B:用loop.run_in_executor()(兼容Python 3.7+)

如果你的Python版本低于3.9,可手动指定线程池执行阻塞函数:

import asyncio
import time
from concurrent.futures import ThreadPoolExecutor

def blocking_test_loop():
    loop_counter = 0
    while True:
        print('loop')
        time.sleep(2)
        if loop_counter >= 5:
            break
        loop_counter += 1

async def test_loop():
    loop = asyncio.get_running_loop()
    # 调用线程池执行阻塞函数
    await loop.run_in_executor(ThreadPoolExecutor(), blocking_test_loop)

async def delay_msgs():
    print('run msgs')
    await asyncio.sleep(5)
    print('asdf')
    await asyncio.sleep(10)
    print("qwerty")

async def main():
    task1 = asyncio.create_task(delay_msgs())
    task2 = asyncio.create_task(test_loop())
    await asyncio.gather(task1, task2)

if __name__ == '__main__':
    asyncio.run(main())

原理说明

asyncio的事件循环基于单线程调度,所有异步任务都在该线程内切换执行。如果某个任务执行阻塞操作(如time.sleep、同步IO),整个事件循环会被卡住,直到阻塞结束。将阻塞操作放到线程池后,事件循环线程可继续处理其他任务,等线程池内的阻塞操作完成后再获取结果,从而保证异步特性不受影响。

内容的提问来源于stack exchange,提问作者Umis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 10:55:22