我有一个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 }}
我该如何完成这项任务?
答案 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)