Python – запуск Autobahn | сервер Python asyncio websocket в отдельном подпроцессе или потоке

У меня есть программа GUI на основе tkinter, работающая в Python 3.4.1. У меня есть несколько потоков, запущенных в программе, чтобы получать данные JSON из разных URL-адресов. Я хочу добавить некоторые функции WebSocket, чтобы позволить программе действовать как сервер и разрешать нескольким клиентам подключаться к ней через WebSocket и обмениваться другими данными JSON.

Я пытаюсь использовать сервер Autobahn | Python WebSocket для asyncio.

Сначала я попытался запустить цикл событий asyncio в отдельном потоке в программе GUI. Тем не менее, каждая попытка дает «AssertionError: в потоке« Thread-1 »отсутствует текущий цикл событий.

Затем я попытался создать процесс со стандартным пакетом многопроцессорной библиотеки, который запускал цикл событий asyncio в другом Процессе. Когда я пытаюсь это сделать, я не получаю никаких исключений, но сервер WebSocket также не запускается.

Возможно ли даже запустить цикл событий asyncio в подпроцессе из другой программы Python?

Есть ли способ интегрировать цикл событий asyncio в текущую многопоточную / tkinter-программу?

UPDATE Ниже приведен фактический код, который я пытаюсь запустить для первоначального теста.

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.

3 Solutions collect form web for “Python – запуск Autobahn | сервер Python asyncio websocket в отдельном подпроцессе или потоке”

Во-первых, вы получаете AssertionError: There is no current event loop in thread 'Thread-1'. потому что asyncio требует, чтобы каждый поток в вашей программе имел свой собственный цикл событий, но он будет автоматически создавать цикл событий для вас в основном потоке. Поэтому, если вы asyncio.get_event_loop один раз в основном потоке, он автоматически создаст объект цикла и установит его как значение по умолчанию для вас, но если вы вызовете его снова в дочернем потоке, вы получите эту ошибку. Вместо этого вам нужно явно создать / установить цикл событий при запуске потока:

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

Как только вы это сделаете, вы сможете использовать get_event_loop() в этом конкретном потоке.

Можно запустить asyncio событий asyncio в подпроцессе, запущенном с помощью 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 или использовать multiprocessing контекст «spawn».

Я думаю, что должно быть возможно запустить asyncio событий asyncio в фоновом потоке (или процессе) вашего приложения Tkinter и иметь asyncio событий tkinter и asyncio бок о бок. Вы столкнетесь с проблемами, если попытаетесь обновить графический интерфейс из фонового потока / процесса.

Ответ @dano может быть правильным, но создает новый процесс, который в большинстве случаев является неуместным.

Я нашел этот вопрос в Google, потому что у меня была такая же проблема. Я написал приложение, в котором я хотел, чтобы aps веб-приложения не запускались в основном потоке, и это вызвало вашу проблему.

Я нашел свое альтернативное решение, просто прочитав о циклах событий в документации на python и нашел функции asyncio.new_event_loop и asyncio.set_event_loop, которые решили эту проблему.

Я не использовал AutoBahn, но библиотеку pypi websockets, и вот мое решение

 import websockets import asyncio import threading class WebSocket(threading.Thread): @asyncio.coroutine def handler(self, websocket, path): name = yield from websocket.recv() print("< {}".format(name)) greeting = "Hello {}!".format(name) yield from websocket.send(greeting) print("> {}".format(greeting)) def run(self): start_server = websockets.serve(self.handler, '127.0.0.1', 9091) eventloop = asyncio.new_event_loop() asyncio.set_event_loop(eventloop) eventloop.run_until_complete(start_server) eventloop.run_forever() if __name__ == "__main__": ws = WebSocket() ws.start() 

«Есть ли способ интегрировать цикл событий asyncio в текущую многопоточную / tkinter-программу?»

Да, запустите программу tkinter с помощью цикла событий asyncio. Доказательство концепции.

 '''Proof of concept integrating asyncio and tk loops. Terry Jan Reedy Run with 'python -i' or from IDLE editor to keep tk window alive. ''' import asyncio import datetime as dt import tkinter as tk loop = asyncio.get_event_loop() root = tk.Tk() # Combine 2 event loop examples from BaseEventLoop doc. # Add button to prove that gui remain responsive between time updates. # Prints statements are only for testing. def flipbg(widget, color): bg = widget['bg'] print('click', bg, loop.time()) widget['bg'] = color if bg == 'white' else 'white' hello = tk.Label(root) flipper = tk.Button(root, text='Change hello background', bg='yellow', command=lambda: flipbg(hello, 'red')) time = tk.Label(root) hello.pack() flipper.pack() time.pack() def hello_world(loop): hello['text'] = 'Hello World' loop.call_soon(hello_world, loop) def display_date(end_time, loop): print(dt.datetime.now()) time['text'] = dt.datetime.now() if (loop.time() + 1.0) < end_time: loop.call_later(1, display_date, end_time, loop) else: loop.stop() end_time = loop.time() + 10.1 loop.call_soon(display_date, end_time, loop) # Replace root.mainloop with these 4 lines. def tk_update(): root.update() loop.call_soon(tk_update) # or loop.call_later(delay, tk_update) # Initialize loop before each run_forever or run_until_complete call tk_update() loop.run_forever() 

Я экспериментально запускаю IDLE с этими 4 дополнительными строками, причем замедление наблюдается только тогда, когда синтаксис выделяет 1000 строк.

Interesting Posts

эффективные способы нахождения наибольшего простого множителя числа

Django Unit Testing занимает очень много времени для создания тестовой базы данных

Как найти первый «ключ»? в словаре?

Проблема с большими запросами: GET не выпускает / не перезапускает TCP-соединения, сбои цикла

как использовать «/» (разделитель каталогов) в Linux и Windows?

Потокобезопасный эквивалент времени python.strptime ()?

matplotlib не будет рисовать python3

Сравнение двух файлов csv и получение разницы

Убедитесь, что * тип * файла существует в Python

Excel VLOOKUP эквивалент в пандах

Google App Engine, как создать собственный файловый объект?

Объекты Pickle Queue в python

Регистрация Django Redux: как изменить уникальный идентификатор от имени пользователя до электронной почты и использовать электронную почту в качестве логина

Использование потоковой передачи для сохранения порта управления FTP

Чтение из Python dict, если ключ не может присутствовать

Python - лучший язык программирования в мире.