【问题标题】:Python 3.8 Convert for loop to multiprocessing/multithreadingPython 3.8 将 for 循环转换为多处理/多线程
【发布时间】:2021-05-28 08:21:21
【问题描述】:

我是多处理的新手,如果有人可以在这里指导/帮助我,我将不胜感激。我有以下 for 循环,它从两个函数中获取一些数据。代码是这样的

    for a in accounts:
        dl_users[a['Email']] = get_dl_users(a['Email'], adConn)
        group_users[a['Email']] = get_group_users(a['Id'], adConn)

    print(f"Users part of DL - {dl_users}")
    print(f"Users part of groups - {group_users}")
    adConn.unbind()

这可以正常工作并获得所有结果,但最近我注意到获取用户列表(即 dl_users 和 group_users)需要很长时间。大约需要 14-15 分钟才能完成。我正在寻找可以加快功能的方法,并希望将此 for 循环转换为多处理。 get_group_usersget_dl_users 调用 LDAP,所以我不能 100% 确定是否应该将其转换为多处理或多线程。任何建议都会有很大帮助

【问题讨论】:

  • 请记住,多处理和多线程不是一回事。如果您需要计算大量 I/O 绑定任务,例如网络连接,则使用线程。对于 CPU 密集型任务,请使用多处理。
  • 感谢您的回复,是的,我觉得在这里多处理是正确的方法,感谢您的解释

标签: python python-3.x python-multiprocessing python-multithreading


【解决方案1】:

如 cmets 中所述,多线程适用于 I/O 操作(读取/写入文件、发送 http 请求、与数据库通信),而多处理适用于 CPU 密集型任务(例如转换数据、进行计算...)。根据您的功能执行哪种操作,您需要其中一种。如果它们混合使用,请在内部将它们分开并分析两者中的哪一个真正需要优化,因为多处理和 -threading 都会引入可能不值得添加的开销。

也就是说,在最近的 Python 版本(包括您的 3.8)中应用多处理或多线程的方法非常简单。

多处理

from multiprocessing import Pool


# Pick the amount of processes that works best for you
processes = 4

with Pool(processes) as pool:
    processed = pool.map(your_func, your_data)

其中your_func 是一个应用于your_data 的每个元素的函数,它是一个可迭代对象。如果需要为可调用对象提供一些其他参数,可以使用 lambda 函数:

processed = pool.map(lambda item: your_func(item, some_kwarg="some value"), your_data)

多线程

多线程的 API 非常相似:

from concurrent.futures import ThreadPoolExecutor


# Pick the amount of workers that works best for you.
# Most likely equal to the amount of threads of your machine.
workers = 4

with ThreadPoolExecutor(workers) as pool:
    processed = pool.map(your_func, your_data)

如果您希望避免在内存中存储your_data(如果您需要项目的某些属性而不是项目本身),则可以使用生成器:

processed = pool.map(your_func, (account["Email"] for account in accounts))

【讨论】:

  • 非常感谢您的帮助。我尝试使用多线程dl_users = pool.map(get_dl_users, [(account["Email"] for account in accounts), adConn]) 当我尝试打印dl_users 时如何查看结果它只返回<generator object Executor.map.<locals>.result_iterator at 0x11382a3d0> 我如何等待结果然后继续?您还可以确认这是否是 adConn 作为参数传递的方式
  • 这样你将整个[(account["email"] ...), adConn] 作为map() 的第二个参数传递。该参数应该是一个可迭代的,但您要给它一个可迭代的列表。检查我的最后一个代码示例,了解如何传递第二个参数;要正确传递adConn,请查看“多处理”下的最后一个示例,使用 lambda。
猜你喜欢
  • 1970-01-01
  • 2013-04-13
  • 1970-01-01
  • 1970-01-01
  • 2016-03-31
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
  • 2021-06-29
相关资源
最近更新 更多