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

为何datetime.strptime()会阻塞asyncio.Queue.get()操作?

为什么datetime.strptime()会阻塞asyncio.Queue.get()操作?

问题代码

import time
import asyncio
from datetime import datetime
from functools import partial

def write(queue):

    data = dict(fname = "Stack", lname = "Overflow")
    
    # 注释掉这行代码后程序运行正常
    dob = datetime.strptime("2025-02-12", "%Y-%m-%d")

    queue.put_nowait(data)
    print("Writing to queue complete")
    time.sleep(3600)  # 永久休眠

async def reader(queue):
    loop = asyncio.get_running_loop()
    print("This print means this thread is not blocked")
    while msg := await queue.get():
        print("Got my message", msg)
        loop.call_soon(print, msg)

async def main():
    queue = asyncio.Queue()
    loop = asyncio.get_running_loop()
    loop.run_in_executor(None, partial(write, queue))
    await reader(queue)

asyncio.run(main())

两种运行结果

  • 注释datetime.strptime()后的输出:
Writing to queue complete
This print means this thread is not blocked
Got my message {'fname': 'Stack', 'lname': 'Overflow'}
{'fname': 'Stack', 'lname': 'Overflow'}
  • 保留datetime.strptime()后的输出:
This print means this thread is not blocked
Writing to queue complete

问题根源

根本不是datetime.strptime()在阻塞队列,是你在非事件循环线程里直接调用asyncio.Queue.put_nowait()的操作本身就不安全。

asyncio.Queue是给协程间通信设计的,它的方法只有在事件循环所在的主线程里调用才是安全的。如果要在其他线程(比如run_in_executor启动的线程)里操作队列,必须用loop.call_soon_threadsafe()来包装队列操作。

之前注释掉strptime时能正常运行,纯粹是线程调度的运气好——write线程执行put_nowait的速度太快,队列内部状态没被线程竞争破坏,事件循环线程刚好及时处理了队列的唤醒信号。

而加上strptime后,这个操作让write线程的执行时间稍微变长,线程调度时机发生变化,导致不安全的put_nowait操作破坏了队列的内部状态,使得await queue.get()没有被正确唤醒,后续的打印代码自然就没机会执行。

修复方案

修改write函数,用事件循环的线程安全方法调用队列的put_nowait:

def write(queue, loop):
    data = dict(fname = "Stack", lname = "Overflow")
    dob = datetime.strptime("2025-02-12", "%Y-%m-%d")
    # 用线程安全的方式执行队列put操作
    loop.call_soon_threadsafe(queue.put_nowait, data)
    print("Writing to queue complete")
    time.sleep(3600)

async def main():
    queue = asyncio.Queue()
    loop = asyncio.get_running_loop()
    # 把事件循环对象传给write函数
    loop.run_in_executor(None, partial(write, queue, loop))
    await reader(queue)

修改后不管有没有datetime.strptime(),程序都会正常输出所有内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 12:08:08