如何在Python中实现多线程socket.recv()?

2 投票
2 回答
4119 浏览
提问于 2025-04-16 16:17

我有很多设备需要获取状态更新。现在我只有一个套接字对象,而通过socket.recv()这个方法就能获取状态。在单线程的应用中,这一切都很顺利:

class Device:
    def receive(self):
        log.debug("receive waiting: %r", self.device_id)
        try:
            packet = self.socket.recv(255)
        except Exception as e:
            self.report_socket_error(e)
            self.reconnect()
        log.debug("received response: %r", self.device_id)
d = Device()
d.connect()
while True:
    d.receive()

但是,当把相同的代码放进一个线程类中时,就出现了死锁和一些奇怪的行为。即使加了锁也没有改变什么。我追踪问题发现是socket.recv()这个调用出了问题……那么,如何实现多个线程,每个线程独占一个套接字(一个线程只负责一个套接字),并且能够同时等待数据呢?

提前谢谢你们!

2 个回答

0

你需要从多少个不同的套接字读取数据呢?

  • 如果答案是“只有一个”,那么就只用一个线程。再加一个线程对你没有任何帮助,反而会让事情变得更复杂,就像你发现的那样。
  • 如果答案是“多个”,那么一种组织方式就是每个套接字用一个线程。recv 是一个阻塞操作,这使得使用线程来组织代码变得很有吸引力。每个线程都有自己的套接字,可以随时读取数据。这样做应该不会出现问题或死锁。

    只要没有共享资源,就不需要使用锁。即使你需要共享一些资源(比如日志记录、某些数据存储等),也不要仅仅使用简单的锁——Python 提供了更高级的工具,比如 Queue 模块。

0

我知道这并没有直接回答你关于如何解决死锁问题的提问,但看起来在你的情况下,使用线程可能有点多余:

你可以只用一个线程,利用 select() 来找出哪个套接字有可用的数据,然后处理这些数据。除非处理数据的时间很长,或者你的协议比较复杂,使用 select 应该就足够了,这样可以避免所有与线程相关的问题。

想了解更多细节,可以看看这个链接:http://docs.python.org/howto/sockets.html#non-blocking-sockets

撰写回答