我想知道在使用Pythons套接字时是否真的需要使用例如 threading.Lock
,其中每个线程只从该套接字发送和接收 . 打开和关闭始终由父级处理 .
在搜索答案时,大多数人只是说套接字不是线程安全的,并且需要使用某些东西来序列化它们 . 但没有人真正解释为什么这是必需的 .
其他人说 send
和 recv
在操作系统级别上是线程安全的,因此可以并行使用而不进行序列化(here) . 我不知道我在这里是否正确,但我认为Python使用POSIX套接字的C实现,对吗? (套接字的Windows实现怎么样?)
如果不正确调用 send
和 recv
没有锁,那为什么呢?是否有可能在线程上接收到另一个请求的数据?
1 回答
只要只有一个发送者或接收者,就没有理由必须将呼叫同步到
send
或recv
. 考虑是否有两个线程试图接收消息 . 让我们说,为了便于讨论,client => server消息是8字节长,前4个字节是命令,第二个4字节是某种对象标识符:在这里,两个线程都不会以完整的消息结束 . 现在,很多次都不会发生,你不仅仅是python BTW; C程序也是如此 . )
所以,是的,套接字是"thread-safe",因为正好一个线程的
recv
将获得给定的数据字节,并且没有什么可以阻止两个线程同时调用recv
. 操作系统在TCP(SOCK_STREAM
)套接字中没有任何内容,这将确保一个线程接收到整个"message"(任何长度大于单个字节) .如果你有两个线程,一个只接收,一个只发送,那么就没有竞争,也不需要锁定来维护一致的数据流 .
UDP套接字OTOH是"message-oriented"所以它们没有相同的问题 . 每个
send
或recv
都提供不可分割的数据报 . 接收线程不会获得数据报的一部分 . 它获取整个数据报或没有任何内容(尽管由于缓冲区空间不足,数据报可能会被截断;但在这种情况下,其余部分只是被丢弃而不会被传递到下一个接收线程) .