我有一个多线程程序(大约20个线程;生成器/消费者混合有很多队列)
在其中一个线程中,它从队列中弹出字符串并将其发送到远程程序
# it starts the thread like this
workQ = Queue.Queue()
stop_thr_event = threading.Event()
t = threading.Thread( target=worker, args=(stop_thr_event,) )
# in the thread's worker function
def worker(stop_event):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = (myhost, int(myport))
sock.connect(server_address)
while True:
try:
item = workQ.get(timeout=1)
if print_only:
print item
else:
if item.startswith("key:"):
item = "{%s}" % item
sock.sendall(item)
workQ.task_done()
except Queue.Empty, msg:
if stop_event.isSet():
break
间歇性地,我的程序将挂起,没有任何线程正在做任何工作
经过反复试验,我发现我的程序只挂起了这个运行的线程
我唯一的猜测是sendall()正在占用GIL而我的整个程序都挂起了
1)这是否是一个看似合理的理论? 2)如果我的理论是正确的,我能做什么让sendall()不会占用GIL?使它成为非阻塞发送?
答案 0 :(得分:2)
你错了。没有网络活动持有GIL,sendall()也不例外!
item=workQ.get()
socket.sendall() **# may take long time here.**
workQ.task_done()
因为sendall()可能需要很长时间,而其他使用workQ 的线程在调用task_done()之前无法轮流运行 ==>这就是为什么你的整个程序似乎都处于悬空状态。
答案 1 :(得分:1)
GIL-hogging不会导致程序挂起。它可能会损害程序的性能,但这与悬挂相去甚远。您更有可能遇到某种形式的deadlock。 GIL不能参与死锁,因为解释器不断释放并重新获取它,获取或释放GIL通常不依赖于获取或释放任何其他资源,其他锁也不依赖于GIL。
你对stop_thr_event
锁的使用是相当特殊的。对于主人来说,简单地放一系列"我们已经完成,回家"对象进入队列,并让工作人员检测这些对象并在识别时返回。这也与经验法则相关,timeout
的唯一正确值是零和无穷大(即没有超时)。在当前情况下,您的工作人员正在等待一秒钟,检查事件,等待一秒钟等等,并polling is a Bad Thing。
现在,如果通过"挂起"你的意思是程序在恢复之前偶尔冻结很短的时间, 表现不佳,所以也许GIL可能是罪魁祸首。但是套接字不是问题。问题是你可能有大量的线程竞争GIL(因为他们都试图每秒轮询一次),如果你仍然在2.x,你就不会这样做。有the new GIL。消除民意调查将有助于此。