如何在Python中进行异步文件复制?

时间:2015-02-03 17:39:12

标签: python file parallel-processing

我正在处理Python中的一个函数,该函数接收文件路径列表和目标列表,并将每个文件复制到每个给定目标。我有这个功能的复制部分正常工作,但我需要能够异步运行这个功能,除了gui的操作,这样可以减少填写每个表格的时间。"每次将文件复制到所有目录时,我还需要复制功能来通知用户。

我已经对如何做到这一点进行了一些研究,但是每个选项都有很大不同,例如使用不同的库。你怎么建议我这样做?

3 个答案:

答案 0 :(得分:2)

由于您的问题是IO限制,我建议您查看threading模块。结合Queue模块,您将实现这一目标。

答案 1 :(得分:1)

我同意通过Queue进行通信的线程是一个很好的解决方案。这是一个示例类:

import os, shutil, threading, Queue

class FileCopy(threading.Thread):
    def __init__(self, queue, files, dirs):
        threading.Thread.__init__(self)
        self.queue = queue
        self.files = list(files)  # copy list
        self.dirs = list(dirs)    # copy list
        for f in files:
            if not os.path.exists(f):
                raise ValueError('%s does not exist' % f)
        for d in dirs:
            if not os.path.isdir(d):
                raise ValueError('%s is not a directory' % d)

    def run(self):
        # This puts one object into the queue for each file,
        # plus a None to indicate completion
        try:
            for f in self.files:
                try:
                    for d in self.dirs:
                        shutil.copy(f, d)
                except IOError, e:
                    self.queue.put(e)
                else:
                    self.queue.put(f)
        finally:
            self.queue.put(None)  # signal completion

以下是如何使用此类的示例:

queue = Queue.Queue()
files = ['a', 'b', 'c']
dirs = ['./x', './y', './z']
copythread = FileCopy(queue, files, dirs)
copythread.start()
while True:
    x = queue.get()
    if x is None:
        break
    print(x)
copythread.join()

答案 2 :(得分:0)

早期answer中的线程始终按顺序执行,而没有任何并行性。进行一些更改,就可以使IO绑定的作业一起运行,以便线程的完成取决于文件的大小。

我在answer中对代码进行了微小的更改,并尝试验证最小的文件先完成,而其他IO操作在后台继续进行。

import os, shutil, threading, queue

class FileCopy(threading.Thread):
    def __init__(self, queue, files, dirs):
        threading.Thread.__init__(self)
        self.queue = queue
        self.files = list(files)  # copy list
        self.dirs = list(dirs)    # copy list
        for f in files:
            if not os.path.exists(f):
                raise ValueError('%s does not exist' % f)
        for d in dirs:
            if not os.path.isdir(d):
                raise ValueError('%s is not a directory' % d)

    def run(self):
        # This puts one object into the queue for each file
        try:
            for f in self.files:
                try:
                    for d in self.dirs:
                        shutil.copy(f, d)
                except IOError as e:
                    self.queue.put(e)
                else:
                    self.queue.put(f)
        finally:
            pass


queue = queue.Queue()
files = ['a', 'b', 'c']
dirs = ['./x', './y', './z']
thlist = []

for file in files:
    copythread = FileCopy(queue, [file], dirs)
    thlist.append(copythread)

for th in thlist:
    th.start()

for file in files:
     x = queue.get()
     print("Finished copying " + x)

for th in thlist:
    th.join()