多核CPU上多线程文件复制速度远慢于单线程
我正在尝试用Python写一个多线程程序,以加快复制不到1000个的.csv文件的速度。但是,运行多线程代码的速度比顺序复制还要慢。我用profile.py
来测量代码的运行时间。我确定我一定是哪里做错了,但不太清楚是什么问题。
环境:
- 四核CPU。
- 有两个硬盘,一个存放源文件,另一个是目标硬盘。
- 1000个csv文件,大小从几KB到10MB不等。
方法:
我把所有文件路径放在一个队列里,然后创建4到8个工作线程,从队列中取出文件路径并复制指定的文件。在任何情况下,多线程代码的速度都没有更快:
- 顺序复制需要150到160秒
- 多线程复制却超过230秒
我认为这是一个受I/O限制的任务,所以多线程应该能提高操作速度。
代码:
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()')
6 个回答
我认为这是一个输入输出(I/O)密集型的任务,使用多线程应该能加快操作速度,我的想法有什么问题吗?
有的。
标点符号太多了。只需要一个就行。问号“?”就可以了。
你的想法是错的。多线程有时对CPU密集型任务有帮助,但对I/O密集型任务是没用的。绝对没用。
在一个进程中,所有线程都得等着,直到其中一个线程完成I/O操作。
那用协程来做这个工作可以吗?
不可以。
如果你想进行大量的I/O操作,就需要很多进程。
比如说你要复制1000个文件,那就需要很多很多进程。每个进程负责复制一部分文件。
我觉得可以确认这是一个磁盘输入输出的问题。我在我的电脑上做了一个类似的测试,从一个非常快的网络服务器复制文件到它自己上,我发现使用你上面提供的代码(4个线程)后,速度几乎提高了1倍。我测试的内容是复制4137个文件,总共16.5G:
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个线程的情况下,我的速度提升非常明显。我使用的是一台非常快的电脑,并且网络连接也很快,所以我可以安全地认为你遇到了输入输出的限制。
另外,看看我在这里得到的回复:使用Python的多进程/多线程来加速文件复制。我还没机会试这段代码,但有可能gevent会更快。
- Spencer
当然会慢。硬盘在文件之间不断地寻找位置。你认为多线程会让这个任务更快的想法完全是错误的。限制速度的因素是你从硬盘读取或写入数据的速度,而每次从一个文件跳到另一个文件的过程都会浪费时间,这些时间本可以用来传输数据。