Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python wait不会返回具有线程中设置的值的future值_Python_Python Asyncio - Fatal编程技术网

Python wait不会返回具有线程中设置的值的future值

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生成(自): """ 创建未来并在结果用完时打印结

此代码应打印“hi”3次,但并不总是打印

我制作了一个gif,显示正在执行的代码:

从异步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
    中出现此问题的内容
异步IO函数是,除非另有明确说明。要从另一个线程执行
set_result
,您需要调用它

但是在您的情况下,这不起作用,因为
A.start
创建的事件循环与主线程执行的事件循环不同。这会产生问题,因为在一个循环中创建的未来无法在另一个循环中等待。因此,也因为不需要创建多个事件循环,您应该将事件循环实例传递给
A.start
,并将其用于异步需求

但是-当从主线程使用事件循环时,
A.start
无法调用
run\u,直到\u complete()
,因为这将尝试运行已经运行的事件循环。相反,它必须调用以将协程提交到主线程中运行的事件循环。这将返回一个
concurrent.futures.Future
(不要与asyncio
Future
混淆),其
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
(不要与asyncio
Future
混淆),其
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我认为问题在于,您在运行和等待未来时使用了不同的事件循环。来自不同事件循环的未来不会同时发生,您应该使用一个事件循环来满足所有异步需求。(这就是事件循环的设计用途。)当我收到一个运行时错误说