Python - 在单独的子进程或线程中运行高速公路|Python asyncio websocket 服务器 [英] Python - Running Autobahn|Python asyncio websocket server in a separate subprocess or thread

查看:41
本文介绍了Python - 在单独的子进程或线程中运行高速公路|Python asyncio websocket 服务器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在 Python 3.4.1 中运行的基于 tkinter 的 GUI 程序.我在程序中运行了几个线程来从各种 url 获取 JSON 数据.我想添加一些 WebSocket 功能,以便允许程序充当服务器并允许多个客户端通过 WebSocket 连接到它并交换其他 JSON 数据.

I have a tkinter based GUI program running in Python 3.4.1. I have several threads running in the program to get JSON data from various urls. I am wanting to add some WebSocket functionality to be able to allow program to act as a server and allow several clients to connect to it over a WebSocket and exchange other JSON data.

我正在尝试将 Autobahn|Python WebSocket 服务器用于 asyncio.

I am attempting to use the Autobahn|Python WebSocket server for asyncio.

我首先尝试在 GUI 程序下的单独线程中运行 asyncio 事件循环.但是,每次尝试都会给出断言错误:线程 'Thread-1' 中没有当前事件循环.

I first tried to run the asyncio event loop in a separate thread under the GUI program. However, every attempt gives 'AssertionError: There is no current event loop in thread 'Thread-1'.

然后我尝试使用标准库多处理包生成一个进程,该包在另一个进程中运行 asyncio 事件循环.当我尝试这个时,我没有得到任何异常,但 WebSocket 服务器也没有启动.

I then tried spawning a process with the standard library multiprocessing package that ran the asyncio event loop in another Process. When I try this I don't get any exception but the WebSocket server doesn't start either.

是否可以在另一个 Python 程序的子进程中运行 asyncio 事件循环?

Is it even possible to run an asyncio event loop in a subprocess from another Python program?

有没有办法将 asyncio 事件循环集成到当前的多线程/tkinter 程序中?

Is there even a way to integrate an asyncio event loop into a currently multithreaded/tkinter program?

更新下面是我尝试为初始测试运行的实际代码.

UPDATE Below is the actual code I am trying to run for an initial test.

from autobahn.asyncio.websocket import WebSocketServerProtocol
from autobahn.asyncio.websocket import WebSocketServerFactory
import asyncio
from multiprocessing import Process

class MyServerProtocol(WebSocketServerProtocol):

   def onConnect(self, request):
      print("Client connecting: {0}".format(request.peer))

   def onOpen(self):
      print("WebSocket connection open.")

   def onMessage(self, payload, isBinary):
      if isBinary:
         print("Binary message received: {0} bytes".format(len(payload)))

      else:
         print("Text message received: {0}".format(payload.decode('utf8')))

      ## echo back message verbatim
      self.sendMessage(payload, isBinary)

   def onClose(self, wasClean, code, reason):
      print("WebSocket connection closed: {0}".format(reason))

def start_server():
   factory = WebSocketServerFactory("ws://10.241.142.27:6900", debug = False)
   factory.protocol = MyServerProtocol
   loop = asyncio.get_event_loop()
   coro = loop.create_server(factory, '10.241.142.27', 6900)
   server = loop.run_until_complete(coro)
   loop.run_forever()
   server.close()
   loop.close()


websocket_server_process = Process(target = start_server)
websocket_server_process.start()

其中大部分直接来自 Autobahn|Python 的 asyncio 示例代码.如果我尝试将它作为进程运行,它不会做任何事情,没有客户端可以连接到它,如果我运行 netstat -a 则没有使用端口 6900.如果只是在主程序中使用 start_server() 它会创建 WebSocket 服务器.

Most of it is straight from the Autobahn|Python example code for asyncio. If I try to run it as a Process it doesn't do anything, no client can connect to it, if I run netstat -a there is no port 6900 being used. If just use start_server() in the main program it creates the WebSocket Server.

推荐答案

首先,您收到 AssertionError: There is no current event loop in thread 'Thread-1'. 因为 asyncio 要求你程序中的每个线程都有自己的事件循环,但它只会在主线程中自动为你创建一个事件循环.因此,如果您在主线程中调用 asyncio.get_event_loop 一次,它将自动创建一个循环对象并将其设置为您的默认值,但是如果您在子线程中再次调用它,您将得到那个错误.相反,您需要在线程启动时显式创建/设置事件循环:

First, you're getting AssertionError: There is no current event loop in thread 'Thread-1'. because asyncio requires each thread in your program to have its own event loop, but it will only automatically create an event loop for you in the main thread. So if you call asyncio.get_event_loop once in the main thread it will automatically create a loop object and set it as the default for you, but if you call it again in a child thread, you'll get that error. Instead, you need to explicitly create/set the event loop when the thread starts:

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

完成此操作后,您应该能够在该特定线程中使用 get_event_loop().

Once you've done that, you should be able to use get_event_loop() in that specific thread.

可以在通过 multiprocessing 启动的子进程中启动 asyncio 事件循环:

It is possible to start an asyncio event loop in a subprocess started via multiprocessing:

import asyncio
from multiprocessing import Process 

@asyncio.coroutine
def coro():
    print("hi")

def worker():
    loop = asyncio.get_event_loop()
    loop.run_until_complete(coro())

if __name__ == "__main__":
    p = Process(target=worker)
    p.start()
    p.join()

输出:

hi

唯一需要注意的是,如果您在父进程和子进程中启动事件循环,如果您在 Unix 平台上,则需要在子进程中显式创建/设置新的事件循环(由于Python 中的错误).它应该可以在 Windows 上正常工作,或者如果您使用spawn"multiprocessing 上下文.

The only caveat is that if you start an event loop in the parent process as well as the child, you need to explicitly create/set a new event loop in the child if you're on a Unix platform (due to a bug in Python). It should work fine on Windows, or if you use the 'spawn' multiprocessing context.

我认为应该可以在 Tkinter 应用程序的后台线程(或进程)中启动 asyncio 事件循环,并且同时拥有 tkinterasyncio 事件循环并行运行.如果您尝试从后台线程/进程更新 GUI,您只会遇到问题.

I think it should be possible to start an asyncio event loop in a background thread (or process) of your Tkinter application and have both the tkinter and asyncio event loop run side-by-side. You'll only run into issues if you try to update the GUI from the background thread/process.

这篇关于Python - 在单独的子进程或线程中运行高速公路|Python asyncio websocket 服务器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆