Python 3.x concurrent.futures.Future能否转换为asyncio.Future?

Python 3.x concurrent.futures.Future能否转换为asyncio.Future?,python-3.x,python-asyncio,python-multithreading,concurrent.futures,Python 3.x,Python Asyncio,Python Multithreading,Concurrent.futures,在编写多线程代码多年后,我正在练习asyncio 注意到一些我觉得奇怪的事情。在asyncio和concurrent中都有一个Future对象 from asyncio import Future from concurrent.futures import Future 我猜每个人都有自己的角色 我的问题是,我是否可以将concurrent.future.future转换为asyncio.future(或相反) 我的问题是,我是否可以将concurrent.future.future转换为a

在编写多线程代码多年后,我正在练习
asyncio

注意到一些我觉得奇怪的事情。在
asyncio
concurrent
中都有一个
Future
对象

from asyncio import Future
from concurrent.futures import Future
我猜每个人都有自己的角色

我的问题是,我是否可以将
concurrent.future.future
转换为
asyncio.future
(或相反)

我的问题是,我是否可以将
concurrent.future.future
转换为
asyncio.future
(或相反)

如果“传输”是指将一个转换为另一个,是的,这是可能的,尽管桥接阻抗失配可能需要一些工作

要将转换为,可以调用
asyncio.wrap\u future
。返回的asyncio未来将在asyncio事件循环中等待,并将在底层线程未来完成时完成。这就是事实

没有将asyncio future直接转换为concurrent.futures的公共功能,但是有一个函数,它接受一个协程,将其提交到一个事件循环,并返回一个并发future,该并发future在asyncio future执行时完成。这可用于有效地将任何异步IO可等待的未来转换为并发未来,如下所示:

def to_concurrent(fut, loop):
    async def wait():
        await fut
    return asyncio.run_coroutine_threadsafe(wait(), loop)
返回的未来将像您预期的并发未来一样运行,例如,它的方法将阻塞等。您可能需要注意的一点是,添加到并发未来的回调将在标记未来已完成的线程中运行,在本例中是事件循环线程。这意味着,如果添加了一些已完成的回调,则需要小心不要在它们的实现中调用阻塞调用,以免阻塞事件循环

请注意,调用
run\u coroutine\u threadsafe
需要事件循环在其他线程中实际运行。(例如,您可以启动一个后台线程并让它执行
循环。永远运行)

对于“并发未来到异步未来”部分,我使用了一个实用程序

from typing import List, Any
from concurrent.futures.thread import ThreadPoolExecutor
import asyncio


class AsyncThreadPool(ThreadPoolExecutor):
    _futures: List[asyncio.Future]
    _loop: asyncio.AbstractEventLoop

    def __init__(self, max_workers=None):
        super().__init__(max_workers)
        self._futures = []

    def queue(self, fn):
        self._loop = asyncio.get_event_loop()
        fut = self._loop.create_future()
        self._futures.append(fut)
        self.submit(self._entry, fn, fut)

    def queueAsync(self, coroutine):
        def newLoop():
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            return loop.run_until_complete(coroutine)
        self.queue(newLoop)

    def _entry(self, fn, fut: asyncio.Future):
        try:
            result = fn()
            self._loop.call_soon_threadsafe(fut.set_result, result)
        except Exception as e:
            self._loop.call_soon_threadsafe(fut.set_exception, e)

    async def gather(self) -> List[Any]:
        return await asyncio.gather(*self._futures)
您可以这样使用它:

with AsyncThreadPool() as pool:
    # Queue some sync function (will be executed on another thread)
    pool.queue(someHeavySyncFunction)
    # Queue a coroutine that will be executed on a new event loop running on another thread
    pool.queue(otherAsyncFunction())

    # Gather results (non blocking for your current loop)
    res: List[Any] = await pool.gather()

asyncio中有一个名为
wrap\u future
的函数

将concurrent.futures.Future对象包装到asyncio.Future对象中


请参见

不确定是否完全重复,但肯定相关:谢谢。阅读它,那里有一个比较,对我来说还没有答案。mkrieger1的帖子很有帮助。我不知道你所说的转移到另一个是什么意思,因为
AsyncPool
已经在事件循环中运行,
queueAsync
只调用
self.\u futures.append(asyncio.create\u task(coroutine))
?在asyncio中创建多个事件循环有点像反模式。