【问题标题】:Implementation of multithreading using concurrent.future in Python在 Python 中使用 concurrent.future 实现多线程
【发布时间】:2021-08-25 14:10:11
【问题描述】:

我编写了一个 python 代码,将原始数据(STM 显微镜)转换为 png 格式,它可以在我的 Macbook Pro 上完美运行。

以下是简化的 Python 代码:

for root, dirs, file in os.walk(path):
    for dir in dirs:
        fpath = path +'/'+ dir
        os.chdir(fpath)
        spaths=savepath +'/'+ dir
        if os.path.exists(spaths) ==False:
           os.mkdir(spaths)

         for files in glob.glob("*.sm4"):
             for file in files:     
                 data_conv (files, file, spaths)

但 100 个文件确实需要 30 - 40 分钟。

现在,我想使用多线程技术(使用“并发未来”库)减少处理时间。以“Python 线程教程”的 YouTube 视频为例,尝试修改 Python 代码。

但我必须在 executor.map() 方法中传递太多参数,例如“root”、“dirs.”、“file”。我不知道如何进一步解决这个问题。

下面是简化的多线程 Python 代码

def raw_data (root, dirs, file):
    for dir in dirs:
        fpath = path +'/'+ dir
        os.chdir(fpath)
        spaths=savepath +'/'+ dir
        if os.path.exists(spaths)==False:
            os.mkdir(spaths)

        for files in glob.glob("*.sm4"):
            for file in files:
                data_conv(files, file, spaths)

with concurrent.futures.ThreadPoolExecutor() as executor:
     executor.map(raw_data, root, dirs, file)

NameError: name 'root' is not defined

感谢您的任何建议。

【问题讨论】:

  • 如果工作负载受 CPU 限制,您应该改用 concurrent.futures.ProcessPoolExecutor,因为由于 GIL,Python 线程不会同时运行。您是否需要用for root, dirs, file in os.walk(path): 结束对executor.map 的呼叫?
  • 对不起,我不是这里的专家,我不知道什么是 GIL。但是,我需要通过多线程或多处理来减少处理时间。 ............. {您是否需要将您对 executor.map 的调用包装为 os.walk(path) 中的 root、dirs、文件:?} YES
  • 除非您受 IO 限制(大量网络/API 调用、写入/读取文件),否则多处理是您最好的选择。 GIL 防止线程并发(同时)运行
  • 任何示例或建议都有助于理解实现代码。

标签: python python-3.x multithreading python-multithreading concurrent.futures


【解决方案1】:

感谢 Iain Shelvington 和 Thenoneman 的建议。

Pathlib 确实减少了我在代码中的混乱情况。

“ProcessPoolExecutor”在我的 CPU 密集型功能中工作。

  with concurrent.futures.ProcessPoolExecutor() as executor:
        executor.map(raw_data, os.walk(path))

【讨论】:

    【解决方案2】:

    首先,正如 Iain Shelvington 所指出的,data_conv 似乎是一个 CPU 密集型功能,因此您不会注意到 ThreadPoolExecutor 的改进,请使用 ProcessPoolExecutor。其次,您必须将参数传递给函数调用的每个实例,即将参数列表传递给raw_data。假设rootfile 是相同的并且dirs 是一个列表:

    with concurrent.futures.ProcessPoolExecutor() as executor:
        results = executor.map(raw_data, [root]*len(dirs), dirs, [file]*len(dirs)
        for result in results:
            # Collect you results
    

    附带说明,您可能会发现使用pathlib 处理文件系统更令人愉悦,它也是自 Python 3.4 以来内置的

    【讨论】:

      猜你喜欢
      • 2021-10-26
      • 1970-01-01
      • 2022-09-27
      • 1970-01-01
      • 2017-05-31
      • 2020-08-03
      • 2021-07-23
      • 1970-01-01
      • 2017-09-22
      相关资源
      最近更新 更多