在继续进入事件循环之前,如何等待asyncio中的响应?

时间:2017-12-02 02:33:35

标签: python asynchronous websocket python-asyncio

我正在使用Python 3.6中的asyncio和websockets包,其目的很简单,即编写一个脚本: (1)连接到websocket; (2)发送多条订阅消息; (3)等待回复;和 (3)将响应推送到MongoDB。

我正在处理大量的websockets,所以我试图使用asyncio来复制一定程度的并行性,我的头痛开始了。

使用像motor和websockets这样的异步软件包,我已经能够编写一个完成此任务的脚本;但是,我正在向我的数据库写重复项。我相信原因是我在asyncio中的调度结构,对MongoDB的写入能够在收到新消息之前多次发生。因此,我想在事件循环中添加一定程度的阻塞,以确保在使用新数据更新结果变量之前不会执行对MongoDB的异步更新。

我能够得到一般的结果;但是,该脚本存储了重复项。我相信这是因为我的异步数据推送功能(update_MonogoDB)上的await进程在收到新消息之前会在循环中多次完成。因此,我的目标是在收到消息时尝试阻止我的异步代码,这样我就可以确保在写入MongoDB之前有新的消息数据可用。在这种情况下,我不能只使用同步代码,因为我是异步打开所有连接。

我知道事件循环具有阻塞属性,但我似乎无法编写嵌套事件循环来创建阻塞。因此,我试图在一个线程中编写事件循环。

有更好的方法吗 - 如何在事件循环中阻止异步函数?

import websockets, asyncio, ast, threading
import motor.asycnio

async def WebSocketConn(url, subscription_msg):
    #Establishing the connection and sending subscription messages
    async with websockets.connect(url) as ws:
        data = {}
        print("Sending subscription")
        await ws.send(json.dumps(subscribe))

        #Defining message collection process
        async def collect_msg():
        try:
            msg = await asyncio.wait_for(ws.recv(), timeout=20)
        except asyncio.TimeoutError:
            try:
                print('Connection timeout - pinging')
                pong_waiter = await ws.ping()
                await asyncio.wait_for(pong_waiter, timeout=10)
            except:
                print('Connection Failed within collect_msg()')

        print("Starting message collection loop")
        while True:
            #create a new loop
            new_loop = asyncio.new_event_loop()

            #assign the loop to another thread
            t = threading.Thread(target=start_new_loop(new_loop))
            t.start()

            #assign some async work to the new thread
            future = asyncio.run_coroutine_threadsafe(collect_msg(), 
            new_loop)
            msg = future.result()    #need blocking on this message
            result = ast.literal_eval(msg)

            await update_MongoDB(result)

async def MultipleConns(conn_details:list):coroutines = 
[WebSocketConn(input[0], input[1], input[2]) for input conn_details] 
completed, pending = await asyncio.wait(coroutines)                             
return completed                                                                

main_loop = asyncio.new_event_loop()
asyncio.set_event_loop(main_loop)
main_loop.set_debug(True)

try:
    main_loop.run_until_complete(MultipleConns(details))
finally:
    main_loop.close()

0 个答案:

没有答案