我正在使用Django频道来支持websockets,并使用他们的组概念向同一组中的多个消费者广播消息。为了在消费者之外发送消息,您需要在其他同步代码中调用异步方法。不幸的是,这在测试时会出现问题。
我开始使用loop.run_until_complete
:
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.ensure_future(channel_layer.group_send(group_name, {'text': json.dumps(message),
'type': 'receive_group_json'}),
loop=loop))
然后堆栈跟踪读取该线程没有事件循环:RuntimeError: There is no current event loop in thread 'Thread-1'.
。为了解决这个问题,我补充道:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(asyncio.ensure_future(channel_layer.group_send(group_name, {'text': json.dumps(message),
'type': 'receive_group_json'}),
loop=loop))
现在堆栈跟踪正在读取RuntimeError: Event loop is closed
,但如果我添加打印语句loop.is_closed()
则会打印False
。
对于上下文,我使用的是Django 2.0,Channels 2和redis后端。
更新:我尝试在Python解释器中运行它(在py.test之外删除移动变量)。当我运行第二个代码块时,我没有收到Event loop is closed
错误(这可能是由于Pytest的结果是否有超时等)。但是,我没有在我的客户端收到群组消息。但是,我确实看到了一份印刷声明:
({<Task finished coro=<RedisChannelLayer.group_send() done, defined at /Users/my/path/to/venv/lib/python3.6/site-packages/channels_redis/core.py:306> result=None>}, set())
更新2 :刷新redis之后,我在py.test中添加了一个fixture来为每个函数和会话范围的事件循环刷新它。这次又来自RedisChannelLayer的另一张照片:
({<Task finished coro=<RedisChannelLayer.group_send() done, defined at /Users/my/path/to/venv/lib/python3.6/site-packages/channels_redis/core.py:306> exception=RuntimeError('Task <Task pending coro=<RedisChannelLayer.group_send() running at /Users/my/path/to/venv/lib/python3.6/site-packages/channels_redis/core.py:316>> got Future <Future pending> attached to a different loop',)>}, set())
答案 0 :(得分:1)
如果SELECT *
, AVG(MonthlyStat) OVER (ORDER BY CAST(REPLACE(Calendar_Date,' ','') AS DATE) ASC
ROWS BETWEEN 11 PRECEDING AND CURRENT ROW) AS YearlyStat
FROM YourTable
期望在另一个线程中驻留在自己的事件循环中,则需要保留该事件循环对象。一旦你拥有了它,你就可以向它提交协同程序并与你的线程同步,如下所示:
channel_layer
答案 1 :(得分:1)
默认情况下,只有主线程获取事件循环,并且在其他线程中调用get_event_loop
将失败。
如果您需要另一个线程中的事件循环 - 例如处理HTTP或WebSockets请求的线程 - 您需要使用new_event_loop
自行创建。之后,您可以使用set_event_loop
,将来的get_event_loop
来电也可以使用。我这样做:
# get or create an event loop for the current thread
def get_thread_event_loop():
try:
loop = asyncio.get_event_loop() # gets previously set event loop, if possible
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
return loop