我正在通过线程解析4个大型XML文件,不知怎的,多线程代码比顺序代码慢?
这是我的多线程代码:
def parse():
thread_list = []
for file_name in cve_file:
t = CVEParser(file_name)
t.start()
thread_list.append(t)
for t in thread_list:
t.join()
result = t.result
for res in result:
print res
PersistenceService.insert_data_from_file(res[0], res[1])
os.remove(res[0])
那就是"更快"代码:
def parse:
thread_list = []
for file_name in cve_file:
t = CVEParser(file_name)
t.start()
t.join()
thread_list.append(t)
for t in thread_list:
result = t.result
for res in result:
print res
PersistenceService.insert_data_from_file(res[0], res[1])
os.remove(res[0])
顺序代码快10分钟,这怎么可能?
答案 0 :(得分:1)
Python使用GIL (Global Interpreter Lock)来确保一次只有一个线程执行Python代码。这样做是为了防止数据争用和其他一些原因。但是,这意味着默认CPython中的多线程几乎不会给你任何代码加速(如果它不会减慢速度,就像你的情况一样)。
要有效地并行化您的工作负载,请查看Python的multiprocessing
模块,该模块将启动不受彼此GIL影响的单独进程
答案 1 :(得分:0)
你在哪里读到多线程甚至多处理应该总是比顺序更快?这完全是错的。 3种模式中哪一种更快取决于要解决的问题,以及瓶颈所在。
select
轮询io 在您的用例中,还有另一个可能的原因:您在连接部分中按顺序等待线程。这意味着如果thread2在thread0之前结束很多,那么你将只在thread0结束后处理它,这是次优的。
这种代码通常更有效,因为只要一个线程完成就允许处理:
active_list = thread_list[:]
while len(active_list) > 0:
for t in active_list:
if not t.is_active():
t.join()
active_list.remove[t]
# process t results
...
time.sleep(0.1)
(*)一些专门用于重型或并行计算的库可以允许Python线程同时运行。一个众所周知的例子是numpy
:使用numpy并在多个线程中执行的复杂操作实际上可以在不同的核上同时运行。技术上这意味着发布 Global Interpreter Lock 。
答案 2 :(得分:0)
如果您正在从旋转的磁盘读取这些文件,那么尝试一次读取4会真的减慢这个过程。
磁盘一次只能真正读取一个,并且必须在它们之间来回移动读/写头很多次才能为不同的读取线程提供服务。这比实际读取数据要花费更长的时间,您将不得不等待它。
另一方面,如果您正在使用SSD,那么您将不会遇到此问题。您可能仍然受到I / O速度的限制,但是4线程的情况应该花费与单线程情况相同的时间。