期货:来自不同线程的结果集

时间:2018-10-31 18:37:53

标签: python-3.x asynchronous python-asyncio coroutine

我有一个http服务器,它在线程中接收一些请求。该http服务器解析收到的数据,并将部分数据发送到其他进程。

此过程的响应可能需要一些时间,并且会在不同线程的回调中收到。

这里的问题是我需要在回调函数中收到部分响应,以响应收到的初始请求,所以我的想法是为此使用asyncio.Task

我的代码如下:

my_futures = dict()

class HTTPHandler(http.server.BaseHTTPRequestHandle):
    do_POST(self):
        #parse data
        asyncio.create_task(self.send_response())

    async def send_response(self):
        global my_futures
        my_futures[uuid] = asyncio.get_event_loop().create_future()
        send_data_to_processB()
        await my_future
        self.send_response()

# Callback where I receive the result from process B
def on_message(message):
    global my_futures
    my_futures[message['uuid']].set_result(message['result'])

if __name__ == '__main__':
    server = http.server.HTTPServer(LISTEN_ADDR, MyHTTPHandler)
    threading.Thread(target=server.serve_forever).start()
    processB.register_callback(on_message)

这种方法的问题是任务没有被执行,并且回调根本不接收结果。

我还尝试将do_POST方法更改为使用asyncio.run(self.send_response())而不是asyncio.create_task,使用这种方法,我的回调获取结果并设置结果,但是协程仅挂在{{1 }}

我该如何完成这项任务?

2 个答案:

答案 0 :(得分:2)

要从事件循环线程之外与asyncio进行交互,请使用call_soon_threadsafe

def on_message(message):
    # my_loop must have been initialized from the main thread
    my_loop.call_soon_threadsafe(
        my_futures[message['uuid']].set_result, message['result'])

但是,这不是代码的唯一问题。您永远不会运行事件循环,因此这些事件都没有执行的机会。您需要在代码中的某个位置放置asyncio.run或同等的字符,通常是在顶层。

由于未为异步编写HTTPServer,因此无法从do_POST调用异步函数。相反,请考虑使用aiohttp

答案 1 :(得分:0)

同上,但不需要保存对事件循环的引用

future = my_futures[message['uuid']]
result = message['result']
future.get_loop().call_soon_threadsafe(future.set_result, result)