在多线程程序中添加 time.sleep 解决了 python 中的 UnicodeDecodeError
Posted
技术标签:
【中文标题】在多线程程序中添加 time.sleep 解决了 python 中的 UnicodeDecodeError【英文标题】:Adding a time.sleep to a multithreaded program solves a UnicodeDecodeError in python 【发布时间】:2016-06-08 03:21:53 【问题描述】:这是我在程序中创建的线程的基本概念:
Main thread
|
ListenerCreator(The WebSocketServer thread) ---> Several listener threads(using log())
所以主线程创建了一个ListenerCreator线程,它连接到多个客户端,并为每个客户端创建一个监听线程。以下是侦听器线程所做的简要说明: 编辑1: 我正在使用 WebSockets 从客户端读取/写入数据。为此,我制作了自己的服务器。有一个标准指定的framing protocol——我正在使用它。在客户端,我只是使用WebSocket.send() 并根据协议中给出的说明“取消屏蔽”消息(请参阅上面链接中的第 5.3 节)。 如果有人要求,我愿意提供服务器代码,但是,这里有一个简短的大纲:
class WebSocketServer:
def start():
#Open server socket, bind to host:port
while True:
#Accept client socket, start a new listener thread for self.log(client)
def log(client):
#Receive data using socket.socket.recv(1024)
#Unmask data as per the protocol
#Decode using data.decode("utf-8")
#Append to data_q while holding data_q_lock
还有其他方法 - 方便发送、关闭、握手等。
同时在主线程中:
while breaking!=len(client_list):
#time.sleep(0.5)
with data_q_lock:
for i in range(len(data_q)):
mes = data_q.pop()
for m in client_list:
if "#DONE"== mes:
breaking += 1
if(mes[:len("#COUNT:")] == "#COUNT:"):
print(mes)
所以基本上这个循环的作用是:遍历data_q,如果消息以“#COUNT”开头,则打印该消息,并在获得一定数量的“#DONE”消息后退出循环。 如果未注释 time.sleep,则此代码有效,但是如果没有 time.sleep,我会在 log 函数中得到 UnicodeDecodeError。 另外我只收到错误 sometimes ,有时程序运行良好。 (顺便说一下,客户端每次都发送相同的数据) 所以,我的问题是,为什么需要 time.sleep ? 我认为这与 python 中的 GIL 有关,因为 time.sleep 发布了 GIL。但是,即使在阅读后我也无法解决问题
【问题讨论】:
请展示您如何从侦听器中的套接字读取数据,这与您的问题非常相关:-) 【参考方案1】:目前没有关于监听器如何从套接字读取数据的信息。然而,这似乎是由于通常对套接字的误解造成的。
通过套接字发送的数据不会被套接字以任何方式“框定”。想象一下,如果我在一个套接字上发送了 3 次“hello”消息。然后,就像在没有换行符的情况下写入文件一样,以下内容将在套接字上流动:
hellohellohello
现在考虑阅读器......在阅读数据时,它如何知道一条消息(“hello”)从哪里开始以及下一条消息从哪里开始?它不能,除非发送者和接收者就应该如何“构建”数据达成一致。这可以通过同意一些协议来完成,例如:
空终止数据;或 固定大小的消息;或 大小前缀消息。当然,它会变得更复杂,即使您已经决定了数据应该如何构建,您也不能保证socket.recv
会返回一个“完整”消息......它只会返回恰好包含的任何数据当时的缓冲区。它可能是半条消息,也可能是半条消息。您的工作是整理从套接字读取的数据并将其划分为消息。
转向您的问题,您正在发送utf-8
数据。读者如何知道它已阅读完整的utf-8
数据消息?最有可能的是,这里发生的事情是您只收到了 部分消息 ...还有更多消息要到达。
特别是,有效的utf-8
字符可能包含多个字节。因此,如果您的部分消息在字符的多字节 utf-8
表示的中间结束,那么您肯定无法对其进行解码。
【讨论】:
谢谢!我添加了更多关于我实际使用套接字的方式的信息。我根据 WebSocket 协议使用大小前缀消息。 您收到UnicodeDecodeError
几乎肯定表明您的数据有效负载不完整...尝试捕获此错误并检查实际帧以确保它是您的想法。 (我假设您意识到 socket.recv(1024)
可能会返回少于 1024 个字节?)以上是关于在多线程程序中添加 time.sleep 解决了 python 中的 UnicodeDecodeError的主要内容,如果未能解决你的问题,请参考以下文章
uWSGI, Thread, time.sleep 使用问题