How to Choose The Method
1. One Task Vs Multiple Tasks
可以通过指定目标函数和每次调用目标函数的参数可迭代对象来向进程池发出多个调用。可以通过以下函数实现这一点:map()、map_async()、imap()、imap_async()、starmap() 和 starmap_async()。
发出单个任务:
- 使用 apply()
- 使用 apply_async()
发出多个任务:
- 使用 map()
- 使用 map_async()
- 使用 imap()
- 使用 imap_unordered()
- 使用 starmap()
- 使用 starmap_async()
2. Blocking vs Non-Blocking
阻塞调用:
- 使用 apply()
- 使用 map()
- 使用 starmap()
非阻塞调用:
- 使用 apply_async()
- 使用 map_async()
- 使用 imap()
- 使用 imap_unordered()
- 使用 starmap_async()
3. Lazy vs Non-lazy
它们立即向进程池发出所有任务。这意味着提供的可迭代对象被遍历,并且所有对目标函数和产生的参数的调用都被转换成任务并保存在内存中。
我们可以将这些函数称为非惰性的。它们包括 map()、map_async()、starmap() 和 starmap_async()。
其他函数则逐一向进程池发出任务,只有在进程池中有空闲空间执行新任务时才会发出。这意味着提供的可迭代对象会逐个遍历,按需创建和发出任务。
我们可以将这些函数称为惰性的,可能更节省内存。它们包括 imap() 和 imap_unordered()。
惰性调用(逐一):
- 使用 imap()
- 使用 imap_unordered()
非惰性调用(一次性):
- 使用 apply()
- 使用 apply_async()
- 使用 map()
- 使用 map_async()
- 使用 starmap()
- 使用 starmap_async()
4. Single Arguments vs Multiple Arguments
没有参数的目标函数:
- 使用 apply()
- 使用 apply_async()
带有一个参数的目标函数:
5. Ordered Results vs Unordered Results
有序结果:
- 使用 map()
- 使用 map_async()
- 使用 imap()
- 使用 starmap()
- 使用 starmap_async()
无序结果:
6. Result Callback vs No Result Callbacks
支持回调函数:
- 使用 apply_async()
- 使用 map_async()
- 使用 starmap_async()
不支持回调函数:
- 使用 apply()
- 使用 map()
- 使用 imap()
- 使用 imap_unordered()
- 使用 starmap()
Compare Methods
1. apply vs apply_async
apply() 和 apply_async() 都可以用于向进程池发出一次性任务。
它们的主要区别如下:
- apply() 函数会阻塞,而 apply_async() 函数不会阻塞。
- apply() 函数会返回目标函数的结果,而 apply_async() 函数会返回一个 AsyncResult 对象。
- apply() 函数不支持回调函数,而 apply_async() 函数支持回调函数。
2. map vs map_async
map() 和 map_async() 都可以用于通过进程池向可迭代对象中的所有项发出调用函数的任务。
它们的主要区别如下:
- map() 函数会阻塞,而 map_async() 函数不会阻塞。
- map() 函数会返回从目标函数返回的可迭代对象,而 map_async() 函数会返回一个 AsyncResult 对象。
- map() 函数不支持回调函数,而 map_async() 函数可以在返回值和错误上执行回调函数。
3. imap vs imap_unordered
imap() 和 imap_unordered() 函数有很多共同点,例如:
- imap() 和 imap_unordered() 都可以通过进程池向可迭代对象中的所有项发出调用函数的任务。
- imap() 和 imap_unordered() 都是 map() 函数的惰性版本。
- imap() 和 imap_unordered() 函数都会立即返回一个返回值的可迭代对象。
然而,这两个函数之间有一个关键的区别:
- imap() 返回的可迭代对象会按照任务完成的顺序逐个产生结果,而 imap_unordered() 函数则会以任务完成的任意顺序产生结果。
4. starmap vs starmap_async
starmap() 和 starmap_async() 都可以用于通过进程池发出调用带有多个参数的函数的任务。
它们的主要区别如下:
- starmap() 函数会阻塞,而 starmap_async() 函数不会阻塞。
- starmap() 函数会返回从目标函数返回的可迭代对象,而 starmap_async() 函数会返回一个 AsyncResult 对象。
- starmap() 函数不支持回调函数,而 starmap_async() 函数可以在返回值和错误上执行回调函数。
5. pool.map vs built-in map()
Pool.map() 函数和内置的 map() 函数都可以遍历提供的可迭代对象,并调用目标函数,将可迭代对象的每个项传递给目标函数执行。
它们的主要区别如下:
- Pool.map() 函数会立即遍历可迭代对象以发出所有任务,而内置的 map() 函数是惰性的,只有在遍历从目标函数返回的返回值的可迭代对象时才会遍历输入的可迭代对象。
- Pool.map() 函数会使用子进程并行执行每个调用目标函数的任务,而内置的 map() 函数会在当前进程中执行每个调用目标函数的任务。
- Pool.map() 函数支持单个可迭代对象作为目标函数的参数,而内置的 map() 函数支持多个可迭代对象,每个可迭代对象对应目标函数的一个参数。
- Pool.map() 函数支持指定块大小(chunksize)来批量调用目标函数的任务,而内置的 map() 函数不支持批量调用目标函数的任务。
Pool.starmap() 和 itertools.starmap() 函数都执行一个目标函数,该函数可能具有多个参数,使用一个提供的可迭代对象,其中每个项都是一个参数迭代器,用于每个函数调用的参数。
它们的主要区别如下:
- Pool.starmap() 函数会立即遍历可迭代对象以发出所有任务,而内置的 itertools.starmap() 函数是惰性的,只有在遍历从目标函数返回的返回值的可迭代对象时才会遍历输入的可迭代对象。
- Pool.starmap() 函数会使用子进程并行执行每个调用目标函数的任务,而内置的 itertools.starmap() 函数会在当前进程中执行每个调用目标函数的任务。
- Pool.starmap() 函数支持指定块大小(chunksize)来批量调用目标函数的任务,而 itertools.starmap() 函数不支持批量调用目标函数的任务。
7. imap() vs map()
imap() 和 map() 都可以用于通过进程池向可迭代对象中的所有项发出调用函数的任务。
它们的主要区别如下:
- imap() 函数逐一向进程池发出任务,而 map() 函数一次性向进程池发出所有任务。
- 在遍历返回值时,imap() 函数会阻塞直到每个任务完成,而 map() 函数会阻塞直到所有任务完成。
Common Questions
1. How to Issue a single Task to the Process Pool
您可以使用 apply() 或 apply_async() 函数向进程池发出单个任务。
2. how to issue Tasks When the Target Function has no arguments
您可以使用 apply() 或 apply_async() 函数发出调用无参数目标函数的任务。
3. how to call map() for a function with multiple Arguments
您可以使用 starmap() 或 starmap_async() 函数向进程池发出针对接受多个参数的目标函数的任务。
4. how to issue tasks Asynchronously
您可以使用 apply_async()、map_async() 和 starmap_async() 函数异步向进程池发出任务。
此外,imap() 和 imap_unordered() 函数不会阻塞。
5. is the imap_unordered() Asynchronous?
不完全正确,但有点像。
imap_unordered() 的异步性质不同于 apply_async()、map_async() 和 starmap_async() 函数。具体来说,imap_unordered() 函数不会返回 AsyncResult 对象。
然而,imap_unordered() 函数和 imap() 函数一样,也不会阻塞。它会立即返回,并且只有在尝试通过遍历返回的可迭代对象来获取任务结果时才会阻塞。
因此,可以说imap_unordered()函数可以异步使用。
6. is there a imap_async() Function
No
这可能是因为 API 提供的 imap_unordered() 函数本身就是异步的,因为它不会阻塞。然而,imap_unordered() 函数确实不会返回 AsyncResult 对象。
7. why Ever use apply()
如果调用 apply() 会阻塞,为什么还要使用它呢?为什么不直接调用函数呢?
主要原因是为了让函数调用在一个单独的子进程中执行。
8. How do you call many different Target Functions
我们可以使用 apply() 或 apply_async() 在循环中调用多个不同的目标函数。
我们也可以使用多个分开的调用来通过 map()、map_async()、imap()、imap_unordered()、starmap() 和 starmap_async() 函数调用多个不同的函数。
9. why bother use imap() instead of map
您会使用 imap() 而不是 map(),这样可以在结果可用时立即开始处理,而不是阻塞等待所有结果可用。
此外,imap() 使用更少的内存,因为它会延迟遍历提供的输入可迭代对象,根据需要逐步发出任务。
10. how do you best set chunksize?
map()、imap() 和 starmap() 函数都接受一个 "chunksize" 参数。
chunksize 指定了要分组并发送到工作子进程中的目标函数调用的数量。
这可以通过减少将数据参数发送到子进程和从子进程接收结果的计算开销,加速整体任务的执行。
最佳的 chunksize 值取决于您的应用程序,具体取决于正在执行的任务、它们的持续时间、发送到每个任务的数据以及从每个任务返回的数据。
您可以通过一些试验和仔细的基准测试找到最佳的 chunksize 值。
一些可以尝试的值包括:
- chunksize=1,即不分块的默认值。
- chunksize = 任务数 / 工作进程数,平均分配。
- chunksize = 任务数 / 工作进程数 * 0.25,稍微少于平均分配的一部分。