仅发送和接收时真的需要通过 Lock 序列化套接字吗?
Is serializing a socket through Lock really necessary when only sending and receiving?
我想知道在使用 Pythons 套接字时是否真的需要使用例如 threading.Lock
,其中每个线程仅从该套接字发送和接收。打开和关闭始终由父级处理。
在搜索答案时,大多数人只是说套接字不是线程安全的,需要使用某种东西来序列化它们。但是没有人真正解释为什么需要这样做。
其他人说 send
和 recv
在操作系统级别上是线程安全的,因此可以并行使用而无需序列化 (here)。我不知道我在这里是否正确,但我认为 Python 使用 POSIX 套接字的 C 实现,对吗? (套接字的 Windows 实现怎么样?)
如果 send
和 recv
在没有锁的情况下被调用是不正确的,那究竟是为什么?线程上是否有可能接收到另一个请求的数据?
只要只有一个发送方或接收方,就没有理由必须同步对 send
或 recv
的调用。考虑是否有两个线程试图接收一条消息。假设,为了便于讨论,客户端 => 服务器消息的长度为 8 个字节,前 4 个字节是命令,后 4 个字节是某种对象标识符:
Thread A: sock.recv(8) obtains first 4 bytes
Thread B: sock.recv(8) obtains second 4 bytes
在这里,两个线程都没有以完整的消息结束。现在,很多时候 不会 发生,你会得到整个 8 字节消息作为一个单元。但这并不能保证,当服务器/网络繁忙并且 OS 网络缓冲区填满并且您有多个线程争夺 CPU 时,这种情况更有可能发生。 (这不仅仅是 python 顺便说一句;C 程序也是如此。)
所以,是的,套接字是 "thread-safe",因为只有一个线程的 recv
将获得给定的数据字节,并且没有什么可以阻止两个线程同时调用 recv
时间。 OS 不会因此而感到困惑。但是 TCP (SOCK_STREAM
) 套接字中没有任何东西可以确保一个线程接收到整个 "message"(任何长度大于一个字节)。
如果你有两个线程,一个只接收,一个只发送,那么就没有竞争,也没有锁定需要保持连贯的数据流。
UDP 套接字 OTOH 是 "message-oriented" 所以他们没有同样的问题。每个 send
或 recv
传递一个不可分割的数据报。接收线程不会获得数据报的 part。它得到整个数据报或什么都没有(尽管数据报可能由于缓冲区不足 space 而被截断;但在那种情况下,其余部分只是被丢弃 而不是 传递给下一个接收线程).
我想知道在使用 Pythons 套接字时是否真的需要使用例如 threading.Lock
,其中每个线程仅从该套接字发送和接收。打开和关闭始终由父级处理。
在搜索答案时,大多数人只是说套接字不是线程安全的,需要使用某种东西来序列化它们。但是没有人真正解释为什么需要这样做。
其他人说 send
和 recv
在操作系统级别上是线程安全的,因此可以并行使用而无需序列化 (here)。我不知道我在这里是否正确,但我认为 Python 使用 POSIX 套接字的 C 实现,对吗? (套接字的 Windows 实现怎么样?)
如果 send
和 recv
在没有锁的情况下被调用是不正确的,那究竟是为什么?线程上是否有可能接收到另一个请求的数据?
只要只有一个发送方或接收方,就没有理由必须同步对 send
或 recv
的调用。考虑是否有两个线程试图接收一条消息。假设,为了便于讨论,客户端 => 服务器消息的长度为 8 个字节,前 4 个字节是命令,后 4 个字节是某种对象标识符:
Thread A: sock.recv(8) obtains first 4 bytes
Thread B: sock.recv(8) obtains second 4 bytes
在这里,两个线程都没有以完整的消息结束。现在,很多时候 不会 发生,你会得到整个 8 字节消息作为一个单元。但这并不能保证,当服务器/网络繁忙并且 OS 网络缓冲区填满并且您有多个线程争夺 CPU 时,这种情况更有可能发生。 (这不仅仅是 python 顺便说一句;C 程序也是如此。)
所以,是的,套接字是 "thread-safe",因为只有一个线程的 recv
将获得给定的数据字节,并且没有什么可以阻止两个线程同时调用 recv
时间。 OS 不会因此而感到困惑。但是 TCP (SOCK_STREAM
) 套接字中没有任何东西可以确保一个线程接收到整个 "message"(任何长度大于一个字节)。
如果你有两个线程,一个只接收,一个只发送,那么就没有竞争,也没有锁定需要保持连贯的数据流。
UDP 套接字 OTOH 是 "message-oriented" 所以他们没有同样的问题。每个 send
或 recv
传递一个不可分割的数据报。接收线程不会获得数据报的 part。它得到整个数据报或什么都没有(尽管数据报可能由于缓冲区不足 space 而被截断;但在那种情况下,其余部分只是被丢弃 而不是 传递给下一个接收线程).