파이썬 - Autobahn 실행 | 파이썬 Asyncio WebScate 서버 별도의 하위 프로세스 또는 스레드에서

StackOverflow https://stackoverflow.com//questions/25063403

문제

Python 3.4.1에서 실행되는 Tkinter 기반 GUI 프로그램이 있습니다. 다양한 URL에서 JSON 데이터를 가져 오기 위해 프로그램에서 몇 개의 스레드를 실행하는 스레드가 있습니다. 프로그램이 서버로 작동하고 여러 클라이언트가 WebSocket을 통해 연결하고 다른 JSON 데이터를 교환 할 수 있도록 일부 WebSocket 기능을 추가 할 수 있습니다.

Autobahn | Python WebSocket 서버용 비동기를 사용하려고합니다.

먼저 GUI 프로그램 아래 별도의 스레드에서 Asyncio 이벤트 루프를 실행하려고했습니다. 그러나 모든 시도는 'AssertionError : Thread'thread-1 '에서 현재 이벤트 루프가 없습니다.

i 그런 다음 다른 프로세스에서 비동기 이벤트 루프를 실행 한 표준 라이브러리 다중 프로세싱 패키지로 프로세스를 산출하도록 시도했습니다. 이 문제를 해결하면 예외가 없으므로 WebSocket 서버가 시작되지 않습니다.

다른 Python 프로그램의 하위 프로세스에서 Asyncio 이벤트 루프를 실행할 수 있습니까?

는 현재 멀티 스레드 / TKInter 프로그램에 Asyncio 이벤트 루프를 통합하는 방법이 있으므로

업데이트 다음은 초기 테스트를 위해 실행하려는 실제 코드입니다.

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 예제 코드에서 비동기를 위해 똑바로 있습니다. 프로세스로 실행하려고하면 아무 것도하지 않아도 클라이언트가 연결할 수 없습니다. netstat -a를 실행하면 포트 6900이 사용되지 않습니다. 메인 프로그램에서 start_server ()를 사용하면 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를 통해 시작된 하위 프로세스에서 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 플랫폼에있는 경우 자식에서 새 이벤트 루프를 명시 적으로 생성 / 설정해야한다는 것입니다. 파이썬 의 버그. 창에서 잘 작동하거나 'Spawn'multiprocessing 컨텍스트를 사용하는 경우

TKInter 응용 프로그램의 백그라운드 스레드 (또는 프로세스)에서 asyncio 이벤트 루프를 시작하고 tkinter 이벤트 루프가 모두 나란히 실행되는 것이 가능해야한다고 생각합니다. 백그라운드 스레드 / 프로세스에서 GUI를 업데이트하려고하면 문제가 발생합니다.

다른 팁

@dano 님이 올바르지 만 대부분의 상황에서는 불명확 한 새로운 프로세스를 만듭니다.

나는 같은 문제가 있었기 때문에 Google 에이 질문을 찍었습니다.나는 웹 소켓 API가 주사에서 실행되지 않고이 문제로 인해 문제를 일으키는 응용 프로그램을 작성했습니다.

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 이벤트 루프를 현재 멀티 스켈 스켈 라디오 프로그램에 통합하는 방법이 있습니까?"

예, Asyncio 이벤트 루프로 Tkinter 프로그램을 실행하십시오.개념 증명.

'''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()
.

나는 4 개의 추가 라인을 4 개의 여분의 라인으로 실험적으로 달리고, 구문이 1000 평가를 강조하는 경우에만 눈에 띄는 시간을 둔화시켰다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top