线程中的python3 websocket

Posted

技术标签:

【中文标题】线程中的python3 websocket【英文标题】:python3 websocket in thread 【发布时间】:2019-10-30 01:39:10 【问题描述】:

我有一个简单的 python tkinter gui,只有几个按钮。当按下按钮时,我想做的就是启动 websocket 连接并开始接收。我可以正常运行代码,但是一旦我尝试将其放入线程中,就会出现错误

RuntimeError: There is no current event loop in thread

所以先试试吧:

import websockets
websocket = websockets.connect(uri, ssl = True)
websocket.recv()

我得到了错误

"Connect object has no attribute 'recv'"

这很奇怪,当我以不同的方式运行它时,我没有收到该错误 当我完全按照文档操作时

   def run_websockets2(self):
        async def hello():
            uri = Websocket_Feed
            # with websockets.connect(uri, ssl=True) as websocket:
            socket = await websockets.connect(uri, ssl=True)
            self.web_socket = socket
            while self.running:
                greeting = await socket.recv()
                print(f"< greeting")
        asyncio.get_event_loop().run_until_complete(hello())

只要我调用“websockets2()”,它就可以工作。但如果我尝试做

self.websocket_thread = threading.Thread(target=self.run_websockets2, args=())
self.websocket_thread.start()

我得到了错误

RuntimeError: There is no current event loop in thread 'web_sockets'

当我使整个函数非异步时,我得到一个错误

def run_websockets(self):
    uri = Websocket_Feed
    # with websockets.connect(uri, ssl=True) as websocket:
    socket = websockets.connect(uri, ssl=True)
    self.web_socket = socket
    while self.running:
        greeting = socket.recv()
        print(f"< greeting")

我得到了错误 RuntimeError:线程“web_sockets”中没有当前事件循环。在 socket = websockets.connect(uri, ssl=True)

我不明白为什么我不能简单地在一个线程中运行这些非异步。非常感谢任何帮助

【问题讨论】:

【参考方案1】:

您在这里有几个不同的错误,这使图片有些混乱。一、关于:

 "Connect object has no attribute 'recv'"

...这只是说websocket 对象没有称为recv 的方法

您遇到的主要问题是尝试从生成的线程调用run_websockets2()。 IE。从主线程调用此方法有效,但从新线程调用此方法失败。

这是预期的行为。这是因为在衍生线程(即主线程以外的线程)中,没有定义异步事件循环。但是为了方便起见,在主线程中定义了一个。因此 asyncio 知道您是从衍生线程还是主线程调用,并且行为不同。有关详细说明,请参阅此答案。 Why asyncio.get_event_loop method checks if the current thread is the main thread?

要解决您的问题,您可以为每个生成的线程创建一个新的事件循环,这样代码将变为:

event_loop = asyncio.new_event_loop()
event_loop.run_until_complete(hello())

而不是

asyncio.get_event_loop().run_until_complete(hello())

或者,您可以将event_loop 存储在一个公共位置,并允许所有生成的线程重用该事件循环。

【讨论】:

感谢@Darren Smith。我认为 pthon 在这种情况下的行为方式很奇怪,但您的答案是正确的。我不知道异步的东西是如何工作的。【参考方案2】:

感谢@Darren Smith,我想发布我是如何实际解决我的代码的。我只是添加了一行代码 "asyncio.set_event_loop(asyncio.new_event_loop())" 到顶部。

 def run_websockets2(self):
        asyncio.set_event_loop(asyncio.new_event_loop())

        async def hello():
            uri = Websocket_Feed
            # with websockets.connect(uri, ssl=True) as websocket:
            socket = await websockets.connect(uri, ssl=True)
            self.web_socket = socket
            while self.running:
                greeting = await socket.recv()
                print(f"< greeting")

        asyncio.get_event_loop().run_until_complete(hello())

我不得不承认,我喜欢 python,但是让代码根据其上下文从根本上以不同的方式运行,并且修复是与上下文无关的一行代码,这似乎是一种非常糟糕的形式。

【讨论】:

以上是关于线程中的python3 websocket的主要内容,如果未能解决你的问题,请参考以下文章

Python3多线程? [复制]

Python3快速入门——Python3并发编程

Python3快速入门Python3并发编程

Python3 多线程

python3 进程和线程

Python3 多线程