python - ThreadPoolExecutor().map 与 ThreadPoolExecutor().submit 有何不同?

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

我只是对我编写的一些代码感到非常困惑。我惊讶地发现:

with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
    results = list(executor.map(f, iterable))

with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
    results = list(map(lambda x: executor.submit(f, x), iterable))

产生不同的结果。第一个生成 f 返回的任何类型的列表,第二个生成 concurrent.futures.Future 对象的列表,然后需要使用它们的 result 进行评估() 方法以获取 f 返回的值。

我主要担心的是,这意味着 executor.map 无法利用 concurrent.futures.as_completed,这似乎是评估我正在对数据库进行一些长期调用的结果,这些调用是可用的。

我完全不清楚 concurrent.futures.ThreadPoolExecutor 对象是如何工作的——天真地说,我更喜欢(稍微冗长一些):

with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
    result_futures = list(map(lambda x: executor.submit(f, x), iterable))
    results = [f.result() for f in futures.as_completed(result_futures)]

在更简洁的 executor.map 之上,以便利用可能的性能增益。我这样做有错吗?

最佳答案

问题是您将 ThreadPoolExecutor.map 的结果转换为列表。如果您不这样做,而是直接迭代生成的生成器,结果仍会按原始顺序生成,但循环会在所有结果准备好之前继续。你可以用这个例子来测试:

import time
import concurrent.futures

e = concurrent.futures.ThreadPoolExecutor(4)
s = range(10)
for i in e.map(time.sleep, s):
    print(i)

保留该顺序的原因可能是因为有时按照您为映射提供的相同顺序获得结果很重要。并且结果可能不会包含在未来的对象中,因为在某些情况下,如果您需要它们,可能需要太长时间才能在列表上执行另一个映射以获取所有结果。毕竟在大多数情况下,下一个值很可能在循环处理第一个值之前就准备好了。这在这个例子中得到了证明:

import concurrent.futures

executor = concurrent.futures.ThreadPoolExecutor() # Or ProcessPoolExecutor
data = some_huge_list()
results = executor.map(crunch_number, data)
finals = []

for value in results:
    finals.append(do_some_stuff(value))

在此示例中,do_some_stuff 可能比 crunch_number 花费更长的时间,如果确实如此,那么在您仍然保留 map 使用方便。

此外,由于工作线程(/进程)从列表的开头开始处理并一直工作到您提交的列表的末尾,因此结果应该按照迭代器已经产生的顺序完成。这意味着在大多数情况下 executor.map 很好,但在某些情况下,例如,如果您处理传递给 map< 的值和函数的顺序无关紧要 运行时间非常不同,future.as_completed 可能更快。

关于python - ThreadPoolExecutor().map 与 ThreadPoolExecutor().submit 有何不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20838162/

相关文章:

python - Flask 如何为 select 标签 HTML 指定默认值

python - 主线程不在主循环 tkinter 中,具有多个 pysimplegui 或 tkinter 对象的多线程 [已解决]

java - 如何让所有线程仅在调用某个方法时等待

python - 是否可以为Python中的函数设置实例变量?

python - 列出对副作用的理解 - 惯用正确还是可憎?

python - 在 Python 中读取和运行数学表达式

python - 如何使用 Django Oauth Toolkit 通过 mobile/otp 登录

java - 我可以在 Junit 测试中检测到泄漏的线程吗?

python - 如何为 pip 设置默认的 python 版本?

python-3.x - 根据其值将 int 数组更改为 string 数组