salge 发表于 2024-1-19 13:21

关于python多进程计算MD5问题。

脚本运行后,OS总是在一个进程里。别的进程一直不动。麻烦大家帮忙找找原因。
import os
import hashlib
import asyncio
import concurrent.futures
import multiprocessing

def calc_md5(file_path):
    # 计算文件的MD5值
    md5 = hashlib.md5()
    with open(file_path, "rb") as f:
      while True:
            data = f.read(1024000)
            if not data:
                break
            md5.update(data)
    return md5.hexdigest()

async def calc_md5_async(file_path, executor):
    # 异步地调用calc_md5函数
    loop = asyncio.get_event_loop()
    md5 = await loop.run_in_executor(executor, calc_md5, file_path)
    return md5

async def main(file_paths, executor):
    # 主函数
    tasks = # 任务列表
    results = await asyncio.gather(*tasks) # 等待所有任务完成
    for file_path, md5 in zip(file_paths, results):
      print(f"{file_path}: {md5}") # 打印结果

def process_start(file_paths):
    # 进程启动函数
    executor = concurrent.futures.ThreadPoolExecutor(max_workers=4) # 线程池
    asyncio.run(main(file_paths, executor)) # 运行主函数

def task_start(dir_path, flag=10000):
    # 任务启动函数
    file_paths = [] # 文件路径列表
    for root, dirs, files in os.walk(dir_path): # 遍历目录
      for file in files:
            file_paths.append(os.path.join(root, file)) # 添加文件路径
    pool = multiprocessing.Pool(processes=4) # 进程池
    for i in range(0, len(file_paths), flag): # 每flag个文件启动一个进程
      pool.apply_async(process_start, (file_paths,)) # 异步地执行进程
    pool.close() # 关闭进程池
    pool.join() # 等待所有进程结束

if __name__ == "__main__":
    task_start("D:\\sd-webui-aki-v4.1\\models\\Stable-diffusion") # 读取指定目录

Zupup 发表于 2024-1-19 14:12

学到了。。。

zxtzly 发表于 2024-1-19 14:18

你最后给的文件夹里面有多少个文件?会不会你的flag给的太多了,总共也没那么多文件

文西思密达 发表于 2024-1-19 14:24

您的代码是用于计算指定目录下所有文件的MD5哈希值的。它首先使用多进程来分割文件,然后使用线程池来异步地计算每个文件的MD5值。从您提供的代码中,我发现了以下几个问题:
[*]线程与进程的混合使用:您同时使用了concurrent.futures.ThreadPoolExecutor和multiprocessing.Pool。这可能导致不必要的复杂性,因为每个子进程都会有一个自己的线程池。通常,选择进程池或线程池应该基于您的具体需求。如果您希望并行处理文件I/O操作(如读取文件),则线程可能是一个好选择。但是,如果您希望并行处理CPU密集型任务,则应该使用进程。
[*]资源管理:当使用multiprocessing.Pool时,确保在不再需要它时调用close()和join()。但在这里,由于您是在外部调用task_start函数,所以这一部分是正确的。
[*]代码可读性:虽然代码功能是明确的,但添加一些注释和文档字符串可能会使其他开发人员更容易理解您的代码。
[*]返回值:您可能想从calc_md5_async函数返回计算出的MD5值,以便在主函数中进一步处理或打印。
[*]错误处理:考虑添加异常处理来捕获潜在的错误,例如文件读取错误或计算MD5时的错误。
[*]硬编码的数字:如max_workers=4和flag=10000,考虑将这些常数定义为变量或常量,以便于管理和修改。
[*]文件路径硬编码:您在if __name__ == "__main__"中硬编码了文件路径。考虑将其作为参数传递或从配置文件中读取。
[*]关闭文件:在calc_md5函数中,您打开了一个文件但没有关闭它。虽然Python会在结束时关闭文件,但最佳实践是明确地关闭文件。
考虑到上述问题,以下是修复后的代码:
import os
import hashlib
import asyncio
import concurrent.futures
import multiprocessing

def calc_md5(file_path):
    """计算文件的MD5值"""
    md5 = hashlib.md5()
    try:
      with open(file_path, "rb") as f:
            while True:
                data = f.read(1024000)
                if not data:
                  break
                md5.update(data)
      return md5.hexdigest()
    except Exception as e:
      print(f"Error calculating MD5 for {file_path}: {e}")
      return None

async def calc_md5_async(file_path, executor):
    """异步地调用calc_md5函数"""
    try:
      return await asyncio.run_in_executor(executor, calc_md5, file_path)
    except Exception as e:
      print(f"Error calculating MD5 for {file_path}: {e}")
      return None

async def main(file_paths, executor):
    """主函数"""
    tasks = # 任务列表
    results = await asyncio.gather(*tasks)# 等待所有任务完成
    for file_path, md5 in zip(file_paths, results):
      print(f"{file_path}: {md5}")# 打印结果

def process_start(file_paths):
    """进程启动函数"""
    executor = concurrent.futures.ThreadPoolExecutor(max_workers=4)# 线程池
    asyncio.run(main(file_paths, executor))# 运行主函数

def task_start(dir_path, flag=10000):
    """任务启动函数"""
    file_paths = []# 文件路径列表
    for root, dirs, files in os.walk(dir_path):# 遍历目录
      for file in files:
            file_paths.append(os.path.join(root, file))# 添加文件路径
    with multiprocessing.Pool(processes=4) as pool:# 使用上下文管理器管理进程池
      for i in range(0, len(file_paths), flag):# 每flag个文件启动一个进程(尽管实际上这里只会有4个进程)
            pool

小刘小刘 发表于 2024-1-19 15:17

学习一下

hjboy11 发表于 2024-1-19 15:27

多进程思路学习一下,不知道楼主实际测试后比单进程真的快吗?

sai609 发表于 2024-1-19 15:45

代码增加,进度条显示,

FlyingDragon 发表于 2024-1-19 19:29

需要看下目录下有多少文件,是不是都分到一个进程里了,另外,md5计算属于计算密集型,启用多线程不会加快速度,倒回拖慢速度

jueyu 发表于 2024-1-19 20:14

使用一下

baliao 发表于 2024-1-20 08:47

文西思密达 发表于 2024-1-19 14:24
您的代码是用于计算指定目录下所有文件的MD5哈希值的。它首先使用多进程来分割文件,然后使用线程池来异步 ...

请问这是AI 回答的还是人工?
页: [1] 2
查看完整版本: 关于python多进程计算MD5问题。