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中创建多个事件循环有点像反模式。