TISUnion / QuickBackupM

A backup / restore plugin, with multiple backup slots
GNU General Public License v3.0
148 stars 20 forks source link

在Windows平台使用多线程进行文件复制 #51

Closed tanhHeng closed 1 year ago

tanhHeng commented 1 year ago

多线程在Windows平台

普通的copytree等复制函数在Windows平台上调度性能较差,无法充分利用硬盘。 使用多线程可将速度提升约300%-600%

添加内容

函数

通过使用shutil.copytree函数先获取文件列表,threading模块建立线程,将待复制的文件按照线程数切分成n份分配给各个线程,开始计算 极大的提高了Windows平台上的备份速度

Config

copy_thread_active

默认值: 4

建立多个线程同时请求硬盘以加快复制速度,该选项控制了建立的线程数量

当该选项设定为0时,关闭多线程复制而采用传统复制方式

测试

环境:

结果:

速度提升了约300%-600%

Fallen-Breath commented 1 year ago

使用线程池,支持 enable_copy_file_range 选项,并暴露拷贝过程中出现的问题的参考实现:

def copy_tree_fast(src_path: str, dst_path: str, ignore=None, copy_function: Callable[[str, str], object] = shutil.copy2):
    with ThreadPoolExecutor(max_workers=max(1, config.copy_thread_active), thread_name_prefix='QBMFileCopier') as pool:
        def threaded_copy(s: str, d: str):
            tasks.append((s, d, pool.submit(copy_function, s, d)))

        tasks = []
        shutil.copytree(src_path, dst_path, ignore=ignore, copy_function=threaded_copy)

    # expose the possible exceptions
    for src, dst, future in tasks:
        try:
            future.result()
        except Exception:
            server_inst.logger.error('Failed to copy file from {} to {}'.format(src, dst))
            raise   
@@ -130,7 +148,7 @@

            server_inst.logger.info('copying {} -> {}'.format(src_path, dst_path))
            if os.path.isdir(src_path):
-               shutil.copytree(src_path, dst_path, ignore=lambda path, files: set(filter(config.is_file_ignored, files)), copy_function=copy_file_fast)
+               copy_tree_fast(src_path, dst_path, ignore=lambda path, files: set(filter(config.is_file_ignored, files)), copy_function=copy_file_fast)
            elif os.path.isfile(src_path):
                dst_dir = os.path.dirname(dst_path)
                if not os.path.isdir(dst_dir):
Fallen-Breath commented 1 year ago

已于 f39a393a1afa48e5de3606ca6d8826519dd471e2 中实现并行复制