编写每个文件的线程比按顺序编写所有文件要慢

时间:2015-11-29 01:34:29

标签: python multithreading

我正在学习Python中的线程,并编写了一个简短的测试程序,它创建了10个csv文件并在每个文件中写入了100k行。我假设让10个线程编写每个自己的文件会更快,但由于某种原因,它比简单地按顺序编写所有文件慢2倍。

我认为这可能与操作系统处理线程的方式有关,但不确定。我在Linux上运行它。

如果有人能说明为何会出现这种情况,我将不胜感激。

多线程版本:

import thread, csv


N = 10  #number of threads

exitmutexes = [False]*N

def filewriter(id_):
    with open('files/'+str(id_)+'.csv', 'wb') as f:
        writer = csv.writer(f, delimiter=',')
        for i in xrange(100000):
            writer.writerow(["efweef", "wefwef", "666w6efw", "6555555"])
    exitmutexes[id_] = True

for i in range(N):
    thread.start_new_thread(filewriter, (i,))

while False in exitmutexes: #checks whether all threads are done
    pass

注意:我试图在while循环中包含一个sleep,以便主线程每隔一段时间释放一次,但这没有实质性的影响。

普通版:

import time, csv


for i in range(10):
    with open('files2/'+str(i)+'.csv', 'wb') as f:
        writer = csv.writer(f, delimiter=',')
        for i in xrange(100000):
            writer.writerow(["efweef", "wefwef", "666w6efw", "6555555"])

2 个答案:

答案 0 :(得分:4)

有几个问题:

  1. 由于Global Interpreter Lock(GIL),Python一次不会为数据生成部分使用多个CPU核心,因此您的数据生成不会因运行多个线程而加速。您需要多处理来改善CPU绑定操作。
  2. 但这并不是问题的核心,因为当您执行I / O(如写入磁盘)时会释放GIL。问题的核心在于您一次只能写入十个不同的地方,这很可能会导致硬盘磁头在硬盘磁头在磁盘中的十个不同位置之间切换时抖动。串行写入在硬盘中几乎总是最快的。
  3. 即使您有CPU绑定操作并使用多处理,使用十个线程也不会在数据生成方面给您带来任何显着优势,除非您实际拥有十个CPU核心。如果您使用的线程数多于CPU核心数,则需要支付线程切换的成本,但是您永远不会加快CPU绑定操作的总运行时间。
  4. 如果使用的线程数多于可用CPU数,则总运行时间总是增加或最多保持不变。使用比CPU核心更多线程的唯一原因是,如果您以交互方式或在与其他系统的管道中消耗线程的结果。有些边缘情况可以通过使用线程来加速设计不良的I / O绑定程序。但设计良好的单线程程序很可能表现得同样好或更好。

答案 1 :(得分:1)

听起来像可怕的GIL(全球翻译锁)

在CPython中,全局解释器锁或GIL是一个互斥锁,它可以防止多个本机线程同时执行Python字节码。这种锁是必要的,主要是因为CPython的内存管理不是线程安全的。(但是,由于GIL存在,其他功能已经增长,取决于它所强制执行的保证。)

这实质上意味着每个python解释器(以及脚本)被锁定到您机器上的一个逻辑核心,并且不会同时执行两个线程,除非您决定生成单独的进程。

有关详细信息,请参阅此页面: https://wiki.python.org/moin/GlobalInterpreterLock