我试图用Python编写一个多线程程序来加速(低于1000).csv文件的复制。多线程代码比顺序方法运行得更慢。我用profile.py
定时代码。我相信我一定做错了什么,但我不确定是什么。
环境:
该方法:
我将所有文件路径放在一个队列中,并创建4-8个工作线程从队列中拉出文件路径并复制指定的文件。在任何情况下,多线程代码都不会更快:
我假设这是一个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()')
当然它比较慢。硬盘驱动器不得不在文件之间不断寻找。您认为多线程会使这项任务更快,这是完全没有道理的。限制速度是指您从磁盘读取数据或将数据写入磁盘的速度,每次从一个文件到另一个文件的搜索都是传输数据所花费的时间。
我假设这是一个更多的I / O绑定任务,多线程应该有助于操作速度,我的方法有什么问题?!
是。
进程中的所有线程必须在一个线程执行I / O时等待。
还是协同工作?!
没有。
如果你想做很多I / O,你需要很多进程。
如果要复制1000个文件,则需要许多进程。每个进程都复制一些文件。
我想我可以验证它是磁盘I / O情况。我在我的机器上进行了类似的测试,从一个非常快速的网络服务器复制回自身,我看到只使用上面的代码(4个线程)几乎提高了1: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个线程中我的速度有了很大的提升。我是一台非常快速的计算机,网络连接非常快,所以我想我可以放心地假设你达到了I / O限制。
那就说,看看我在这里得到的回应:qazxsw poi。我还没有机会尝试这个代码,但gevent可能会更快。
另外,我只是想补充一点,上面的代码有些错误。你应该调用fileQueue.task_done()AFTER shutil.copy(fileName,destPath)..否则最后的文件不会被复制:)
存在Python multiprocess/multithreading to speed up file copying应用程序和cpu bounded
应用程序,当它的顺序版本是cpu有界时,通常你可以从多线程应用程序获得几乎线性的好处。但是当你受到i / o限制时,你将无法获得任何收益,许多操作系统可以向你显示CPU的“繁忙时间百分比”和“磁盘繁忙时间百分比”,这样你就可以知道你的情况。
但是,由于通常顺序代码不是异步的,您最终获取一个文件,然后等待该文件副本,然后是下一个文件。这样就可以避免操作系统拥有文件列表,并根据表面磁盘位置确定读取请求的优先级。
结论:如果您寻求最大性能,请使用单线程,但使用Async API允许操作系统更好地安排读取请求。