使用以下代码作为示例。其主要思想是让一个线程运行同步代码,并向主线程提交一个异步任务(事件循环)。
import asyncio
import concurrent.futures
from time import sleep
loop = asyncio.get_event_loop()
async def a():
print('a')
# simulate IO-bound async code
await asyncio.sleep(0.1)
print('b')
def c():
print('c')
x = loop.create_task(a())
# simulate CPU-bound code
sleep(1)
print('d')
executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
future = loop.run_in_executor(executor, c)
loop.run_forever()
我希望看到的输出
c
a
[wait 0.1 second]
b
[wait 0.9 second]
d
但我真的看到
c
[wait 1 second]
d
a
[wait 0.1 second]
b
根据我的理解,主线程/循环不应该被run_in_executor future阻塞,并且应该在提交后开始运行runnc函数。
已在达尔文上的Python 3.11.5上测试(main,2023年8月24日,15:09:45)[Clang 14.0.3(clang-1403.0.22.14.1)]
有谁能解释这种行为吗?有没有什么方法可以从同步代码触发同步代码?
谢谢你,谢谢
1条答案
按热度按时间j5fpnvbx1#
问题是
create_task
不是thread_safe:尽管没有损坏的数据发生,因为集合,dicts和其他由GIL内部使用的结构,循环并不期望新的事情,它只是在等待它唯一的线程安全任务时出现,这是run_in_executor
调用。使用Rollcio中提供的线程安全调用将在内部执行正确的操作。这段代码的工作方式和你预期的一样: