本文目录导读:

针对Python脚本同步场景的性能优化,核心思路是减少IO操作次数、避免重复处理和使用增量机制,以下是几个实用优化方向:
文件哈希对比(避免全量同步)
import hashlib
import os
def get_file_hash(filepath):
"""只读取前64KB+文件大小进行哈希,避免读全部"""
file_size = os.path.getsize(filepath)
hash_md5 = hashlib.md5(str(file_size).encode()) # 加入大小
with open(filepath, "rb") as f:
# 只读前64KB作为签名
chunk = f.read(65536)
hash_md5.update(chunk)
return hash_md5.hexdigest()
增量同步 - 利用文件修改时间
import os
import shutil
from pathlib import Path
def smart_sync(src, dst, skip_existing=False):
src_path = Path(src)
dst_path = Path(dst)
for file in src_path.rglob('*'):
if file.is_file():
relative = file.relative_to(src_path)
dest_file = dst_path / relative
# 优先使用修改时间和大小判断
if dest_file.exists():
src_stat = file.stat()
dst_stat = dest_file.stat()
if (src_stat.st_mtime <= dst_stat.st_mtime and
src_stat.st_size == dst_stat.st_size):
continue # 跳过不变文件
# 只有真正需要时才进行IO复制
if not skip_existing or not dest_file.exists():
dest_file.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(file, dest_file)
内存映射+分块传输(大文件优化)
import mmap
import os
def chunked_copy(src, dst, chunk_size=8*1024*1024): # 8MB块
file_size = os.path.getsize(src)
with open(src, 'rb') as f_src:
with mmap.mmap(f_src.fileno(), 0, access=mmap.ACCESS_READ) as mm:
with open(dst, 'wb') as f_dst:
for start in range(0, file_size, chunk_size):
end = min(start + chunk_size, file_size)
f_dst.write(mm[start:end])
# 可以添加进度回调
并行同步 + 资源控制
from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
class OptimizedSyncer:
def __init__(self, max_workers=4):
self.semaphore = threading.Semaphore(10) # 限制并发IO数
self.executor = ThreadPoolExecutor(max_workers=max_workers)
def sync_file(self, src, dst):
with self.semaphore: # 控制IO并发量
if os.path.getsize(src) > 100*1024*1024: # 大文件使用分块
self.chunked_copy(src, dst)
else:
shutil.copy2(src, dst)
def batch_sync(self, file_pairs):
futures = []
for src, dst in file_pairs:
if self.need_sync(src, dst): # 预筛选
futures.append(
self.executor.submit(self.sync_file, src, dst)
)
# 收集结果并处理异常
for future in as_completed(futures):
try:
future.result()
except Exception as e:
print(f"Sync failed: {e}")
避免重复IO - 缓存文件属性
functools.lru_cache(maxsize=1000)
def get_file_info(path):
return {
'size': os.path.getsize(path),
'mtime': os.path.getmtime(path),
'exists': os.path.exists(path)
}
def compare_files(src, dst):
src_info = get_file_info(src)
dst_info = get_file_info(dst)
if not dst_info['exists']:
return True
return (src_info['size'] != dst_info['size'] or
src_info['mtime'] > dst_info['mtime'])
使用ranger工具处理大量小文件
import subprocess
def rsync_sync(src, dst):
"""对于大量小文件,使用rsync效率远高于Python"""
cmd = [
'rsync', '-avz', # 归档模式+压缩
'--delete', # 删除目标多余文件
'--partial', # 支持断点续传
'--progress',
src, dst
]
subprocess.run(cmd, check=True)
关键优化点总结
| 优化策略 | 适用场景 | 性能提升 |
|---|---|---|
| 文件哈希跳过 | 大文件 | 减少90%+IO |
| mtime+size对比 | 常规文件 | 减少98%IO |
| 内存映射分块 | >500MB文件 | 提升3-5倍 |
| 并发+信号量 | 多文件同步 | 提升2-4倍 |
| 缓存属性 | 重复访问 | 减少IO延迟 |
| rsync委托 | 大量小文件 | 提升10倍+ |
建议顺序:
- 先实现mtime+size筛选
- 大文件用内存映射分块
- 大量小文件用rsync
- 最后根据情况加并发控制
这样可以从最简单的方式获得最大性能收益。