You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python线程文件备份的Race Condition问题及并行校验需求

多线程文件备份:兼顾并行执行与重复文件校验

你的问题核心是锁的粒度太大,把整个哈希计算、校验、更新的流程都锁住了,导致线程根本没法并行工作。要解决这个问题,关键是缩小锁的范围,只在操作共享的hashList时加锁,把耗时的哈希计算放到锁外面让线程并行处理。

优化思路

  • 提前计算哈希:每个线程先独立计算当前文件的哈希值,这部分操作不需要访问共享数据,完全可以并行执行。
  • 最小化锁范围:只在判断哈希是否已存在、以及添加新哈希到hashList的时候加锁,其他操作都不占用锁。
  • 避免重复计算:原代码里判断和添加时各调用一次hashFile,完全是浪费资源,计算一次就够了。

修改后的完整代码

import threading, hashlib, queue, os


def hashFile(fileName):
    with open(fileName, "rb") as f:
        sha256 = hashlib.sha256()
        while chunk := f.read(4096):
            sha256.update(chunk)
        return sha256.hexdigest()


def backupFile(q):
    while not q.empty():
        fileName = q.get()
        file_path = filesToBackupPath + fileName
        
        # 锁外计算哈希,线程并行执行这部分耗时操作
        file_hash = hashFile(file_path)
        
        # 仅在操作共享hashList时加锁,缩小锁粒度
        with lock:
            if file_hash in hashList:
                print(f"\033[33m{fileName} 已备份过\033[0m")
            else:
                print(f"\033[32m{fileName} 已备份\033[0m")
                hashList.append(file_hash)
        
        q.task_done()


filesToBackupPath = "yedeklenecekDosyalar/"
fileList = os.listdir(filesToBackupPath)
hashList = []

q = queue.Queue()

for file in fileList:
    q.put(file)

lock = threading.Lock()

for i in range(20):
    t = threading.Thread(target=backupFile, args=(q,))
    t.start()

q.join()

print('\n', len(hashList))

关键改动说明

  • 哈希计算并行化:哈希计算是整个流程里的耗时操作(读文件+哈希运算),现在每个线程可以同时处理不同文件的哈希计算,充分利用多线程的优势。
  • 锁粒度最小化:锁只保护hashList的查询和修改,这部分操作非常快,线程等待锁的时间极短,不会影响并行效率。
  • 减少重复计算:一次计算哈希后复用,既节省CPU和IO资源,也避免了两次计算可能出现的不一致(比如文件在两次计算之间被修改的极端情况)。

如果你的实际备份操作(比如复制文件到备份目录)还没实现,也可以把这部分操作放到锁外面,和哈希计算一样并行执行,进一步提升效率。

内容的提问来源于stack exchange,提问作者newfile.py

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 10:34:56