Python多线程脚本队列空后无法终止问题求助
问题原因及解决方法
核心问题
脚本无法终止的根本原因是队列的q.join()一直阻塞:
q.join()会等待所有通过q.put()放入队列的任务都被调用q.task_done()标记为完成后,才会继续执行后续代码。- 你的
get_sam函数中,取出任务(q.get())后没有调用q.task_done(),导致队列认为任务未完成,q.join()永远不会返回,后续的耗时统计语句也就无法执行。
另外,while not q.empty()的判断存在线程安全问题:当多个线程同时检查队列状态时,可能出现队列已空但线程仍进入循环的情况,导致q.get()阻塞住线程。
修复代码
1. 修改get_sam函数
调整循环逻辑,添加task_done()标记,同时避免使用内置类型名作为变量名:
def get_sam(outfile, header='Server Name'): global q while True: name = q.get() # 收到终止信号时退出循环 if name is None: q.task_done() break print("Queue size: ", q.qsize()) sam_results = min_query_flattened_ci_rel(name, header=header) with open(outfile, 'a') as f: writer = csv.writer(f) # 不要用dict作为变量名,覆盖内置类型 for item in sam_results: writer.writerow(item.values()) # 标记当前任务已完成 q.task_done()
2. 修改主程序逻辑
在放入所有任务后,给每个线程添加一个None作为终止信号,确保线程能正确退出:
if __name__ == '__main__': start_time = time.time() print('{} - Initializing script.'.format(datetime.datetime.now().strftime('%H:%M:%S %m/%d/%Y'))) sample_name_list = get_name_list('samplefile.xlsx', 'Host Name') final_csv_name = 'outputsample.csv' with open(final_csv_name, 'a') as f: writer = csv.writer(f) writer.writerow(['Host Name', 'u_name', 'u_child', 'u_parent', 'u_parent_application', 'u_archer_id']) for name in sample_name_list: q.put(name) # 给每个工作线程发送终止信号 for _ in range(NUM_THREADS): q.put(None) for thread in range(NUM_THREADS): worker = Thread(target=get_sam, args=(final_csv_name, 'Host Name')) worker.daemon = True worker.start() q.join() print('{0} - Completed full script in {1} seconds.'.format((datetime.datetime.now().strftime('%H:%M:%S %m/%d/%Y')), (time.time() - start_time)))
额外优化建议
- 避免使用
list、dict等内置类型名作为变量名(比如你代码中的list = df[header].tolist()),这会覆盖内置函数,引发潜在bug。 - 频繁打开/关闭文件(每次写入都
open(outfile, 'a'))会影响性能,可以考虑给每个线程单独维护文件句柄,或者使用线程锁来控制文件写入的原子性(避免多线程同时写入导致数据错乱)。
内容的提问来源于stack exchange,提问作者inspiris
相关产品推荐
相关产品推荐

