我正在使用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()