Python wait不会返回具有线程中设置的值的future值
此代码应打印“hi”3次,但并不总是打印 我制作了一个gif,显示正在执行的代码:Python wait不会返回具有线程中设置的值的future值,python,python-asyncio,Python,Python Asyncio,此代码应打印“hi”3次,但并不总是打印 我制作了一个gif,显示正在执行的代码: 从异步IO导入获取事件循环,等待,新建事件循环 从线程导入线程 A类: 定义初始化(自): self.fut=无 def启动(自): """ 期望创造一个未来,并因此“嗨” """ 异步def foo(): 尽管如此: 如果self.fut: 自我未来设置结果(“hi”) self.fut=无 新建\u事件\u循环()。运行\u直到完成(foo()) 异步def生成(自): """ 创建未来并在结果用完时打印结
从异步IO导入获取事件循环,等待,新建事件循环
从线程导入线程
A类:
定义初始化(自):
self.fut=无
def启动(自):
"""
期望创造一个未来,并因此“嗨”
"""
异步def foo():
尽管如此:
如果self.fut:
自我未来设置结果(“hi”)
self.fut=无
新建\u事件\u循环()。运行\u直到完成(foo())
异步def生成(自):
"""
创建未来并在结果用完时打印结果
"""
future=get_event_loop()。创建_future()
self.fut=未来
打印(等待未来)
a=a()
线程(target=a.start).start()
对于范围(3)内的uu:
获取事件循环()。运行循环直到完成(a.make())
这是由等待未来引起的,因为当我改变
打印(等待未来)
借
而不是将来。完成()
通过
打印(future.result())
代码总是打印“hi”3次
- 我的代码中是否存在导致
中出现此问题的内容wait future
set_result
,您需要调用它
但是在您的情况下,这不起作用,因为A.start
创建的事件循环与主线程执行的事件循环不同。这会产生问题,因为在一个循环中创建的未来无法在另一个循环中等待。因此,也因为不需要创建多个事件循环,您应该将事件循环实例传递给A.start
,并将其用于异步需求
但是-当从主线程使用事件循环时,A.start
无法调用run\u,直到\u complete()
,因为这将尝试运行已经运行的事件循环。相反,它必须调用以将协程提交到主线程中运行的事件循环。这将返回一个concurrent.futures.Future
(不要与asyncioFuture
混淆),其result()
方法可用于等待它执行并传播结果或异常,就像运行直到完成()。由于foo
现在将在与事件循环相同的线程中运行,因此它可以只调用set\u result
,而不调用call\u soon\u threadsafe
最后一个问题是foo
包含一个不等待任何内容的无限循环,这会阻塞事件循环。(请记住,asyncio是基于协作多任务的,而不等待就旋转的协同程序是不协作的。)要解决这一问题,您可以使用foo
监视器,在新的未来可用时触发它
将上述内容应用于代码可以如下所示,根据需要打印“hi”三次:
import asyncio
from asyncio import get_event_loop
from threading import Thread
class A:
def __init__(self):
self.fut = None
self.have_fut = asyncio.Event()
def start(self, loop):
async def foo():
while True:
await self.have_fut.wait()
self.have_fut.clear()
if self.fut:
self.fut.set_result('hi')
self.fut = None
asyncio.run_coroutine_threadsafe(foo(), loop).result()
async def make(self):
future = get_event_loop().create_future()
self.fut = future
self.have_fut.set()
print(await future)
a = A()
Thread(target=a.start, args=(get_event_loop(),), daemon=True).start()
for _ in range(3):
get_event_loop().run_until_complete(a.make())
异步IO函数为,除非明确说明。要从另一个线程执行set_result
,您需要调用它
但是在您的情况下,这不起作用,因为A.start
创建的事件循环与主线程执行的事件循环不同。这会产生问题,因为在一个循环中创建的未来无法在另一个循环中等待。因此,也因为不需要创建多个事件循环,您应该将事件循环实例传递给A.start
,并将其用于异步需求
但是-当从主线程使用事件循环时,A.start
无法调用run\u,直到\u complete()
,因为这将尝试运行已经运行的事件循环。相反,它必须调用以将协程提交到主线程中运行的事件循环。这将返回一个concurrent.futures.Future
(不要与asyncioFuture
混淆),其result()
方法可用于等待它执行并传播结果或异常,就像运行直到完成()。由于foo
现在将在与事件循环相同的线程中运行,因此它可以只调用set\u result
,而不调用call\u soon\u threadsafe
最后一个问题是foo
包含一个不等待任何内容的无限循环,这会阻塞事件循环。(请记住,asyncio是基于协作多任务的,而不等待就旋转的协同程序是不协作的。)要解决这一问题,您可以使用foo
监视器,在新的未来可用时触发它
将上述内容应用于代码可以如下所示,根据需要打印“hi”三次:
import asyncio
from asyncio import get_event_loop
from threading import Thread
class A:
def __init__(self):
self.fut = None
self.have_fut = asyncio.Event()
def start(self, loop):
async def foo():
while True:
await self.have_fut.wait()
self.have_fut.clear()
if self.fut:
self.fut.set_result('hi')
self.fut = None
asyncio.run_coroutine_threadsafe(foo(), loop).result()
async def make(self):
future = get_event_loop().create_future()
self.fut = future
self.have_fut.set()
print(await future)
a = A()
Thread(target=a.start, args=(get_event_loop(),), daemon=True).start()
for _ in range(3):
get_event_loop().run_until_complete(a.make())
现在它不打印任何内容。@ellandor我认为问题在于,您在运行和等待未来时使用了不同的事件循环。来自不同事件循环的未来不会同时发生,您应该使用一个事件循环来满足所有异步需求。(这就是事件循环的设计用途。)当我收到一个运行时错误,说循环已经在运行时,我该怎么做?@ellandor实际上,使用单个循环禁止调用run\u,直到在另一个线程中完成为止,您必须改为使用asyncio.run\u coroutine\u threadsafe
将您的coroutine提交到正在运行的循环。我现在更新了答案以反映这一点,还包括对foo
coroutine的一个不相关问题的修复。现在它不打印任何内容。@ellandor我认为问题在于,您在运行和等待未来时使用了不同的事件循环。来自不同事件循环的未来不会同时发生,您应该使用一个事件循环来满足所有异步需求。(这就是事件循环的设计用途。)当我收到一个运行时错误说