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
相关产品推荐
相关产品推荐

