Multithreaded file copy is far slower than a single thread on a multicore CPU
我正在尝试用python编写一个多线程程序来加速(低于1000.csv文件)的复制。多线程代码的运行速度甚至比顺序方法慢。我用
环境:
- 四核CPU。
- 2个硬盘,其中一个包含源文件。另一个是目的地。
- 1000个csv文件,大小从几KB到10 MB不等。
方法:
我将所有文件路径放在一个队列中,创建4-8个工作线程从队列中提取文件路径并复制指定的文件。在任何情况下,多线程代码都不会更快:
- 连续复制需要150-160秒
- 线程复制需要230秒以上
我假设这是一个I/O绑定的任务,所以多线程应该有助于提高操作速度。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | import Queue import threading import cStringIO import os import shutil import timeit # time the code exec with gc disable import glob # file wildcards list, glob.glob('*.py') import profile # fileQueue = Queue.Queue() # global srcPath = 'C:\\temp' destPath = 'D:\\temp' tcnt = 0 ttotal = 0 def CopyWorker(): while True: fileName = fileQueue.get() fileQueue.task_done() shutil.copy(fileName, destPath) #tcnt += 1 print 'copied: ', tcnt, ' of ', ttotal def threadWorkerCopy(fileNameList): print 'threadWorkerCopy: ', len(fileNameList) ttotal = len(fileNameList) for i in range(4): t = threading.Thread(target=CopyWorker) t.daemon = True t.start() for fileName in fileNameList: fileQueue.put(fileName) fileQueue.join() def sequentialCopy(fileNameList): #around 160.446 seconds, 152 seconds print 'sequentialCopy: ', len(fileNameList) cnt = 0 ctotal = len(fileNameList) for fileName in fileNameList: shutil.copy(fileName, destPath) cnt += 1 print 'copied: ', cnt, ' of ', ctotal def main(): print 'this is main method' fileCount = 0 fileList = glob.glob(srcPath + '\' + '*.csv') #sequentialCopy(fileList) threadWorkerCopy(fileList) if __name__ == '__main__': profile.run('main()') |
当然要慢一点。硬盘必须不断地在文件之间寻找。您认为多线程将使此任务更快是完全不合理的。限制速度是指从磁盘读取数据或将数据写入磁盘的速度,而从一个文件到另一个文件的每次搜索都会浪费传输数据的时间。
我想我可以确认这是磁盘I/O情况。我在我的机器上做了一个类似的测试,从一个非常快的网络服务器复制到它自己上,我发现仅仅使用上面的代码(4个线程),速度几乎提高了1:1。我的测试是复制4137个文件,总计16.5g:
1 2 3 4 5 | Sequential copy was 572.033 seconds. Threaded (4) copy was 180.093 seconds. Threaded (10) copy was 110.155 Threaded (20) copy was 86.745 Threaded (40) copy was 87.761 |
正如您所看到的,当您进入越来越高的线程计数时,会有一些"衰减",但是在4个线程时,我的速度有了很大的提高。我在一台速度非常快的计算机上,网络连接非常快,所以我认为我可以安全地假设您达到了I/O限制。
也就是说,看看我在这里得到的答案:python多进程/多线程加速文件复制。我还没有机会尝试这个代码,但Gevent可能更快。
- 斯宾塞
I assume this is more a I/O bound task, multithread should help the operation speed, anything wrong with my approach?!
对.
标点符号太多。只有一个。"?"是适当的。
你的假设是错误的。多线程帮助CPU绑定(有时)。它无法帮助I/O绑定。从未。
一个进程中的所有线程都必须等待一个线程进行I/O。
or coroutine to do the job?!
不。
如果你想做大量的I/O,你需要很多的过程。
如果您要复制1000个文件,那么您需要许多许多进程。每个进程复制一些文件。
存在
但是,由于通常顺序代码不是异步的,所以您最终会获取一个文件,然后等待该文件的复制,然后等待下一个文件。这样可以避免操作系统拥有文件列表,并根据表面磁盘位置对读取请求进行优先级排序。
结论:如果您希望获得最大的性能,可以使用单线程,但是使用异步API可以让操作系统更好地调度读取请求。
作为旁白,我只是想补充一下,上面的代码有点错误。你应该打电话shutil.copy(文件名,目标路径)之后的filequeue.task_done()。否则将不会复制最后一个文件:)