我正在尝试学习如何使用Python的多进程包,但是我不理解map
和imap
之间的区别。
map
返回一个实际的数组或集合,而imap
返回一个对数组或集合的迭代器,这是否是它们之间的区别?我应该在什么情况下使用其中之一?
此外,我不明白chunksize参数是什么意思。这是传递给每个进程的值的数量吗?
我正在尝试学习如何使用Python的多进程包,但是我不理解map
和imap
之间的区别。
map
返回一个实际的数组或集合,而imap
返回一个对数组或集合的迭代器,这是否是它们之间的区别?我应该在什么情况下使用其中之一?
此外,我不明白chunksize参数是什么意思。这是传递给每个进程的值的数量吗?
这就是它们的区别。你可能使用 imap 而不是 map 的原因之一是如果你想要在计算剩余结果之前开始处理前几个结果。map 会等待所有的结果才返回。
至于 chunksize,有时以较大的数量分配任务会更有效率,因为每次工作进程请求更多任务时,都需要进行 IPC 和同步开销。
chunksize = len(iterable)
,那么所有作业都将分配给单个进程!len(iterable) // numprocesses
是最有用的最大值。权衡是同步开销和 CPU 利用率之间的关系(大的块大小会导致一些进程在其他进程之前完成,浪费潜在的处理时间)。 - Antimonyimap
会从正在运行的 x 个进程中返回第一个结果?即它是否保留顺序?这是否意味着在迭代结果之前仍然必须等待第一个进程完成? - Tjorriemorrie使用imap时,forked调用是并行进行的,而不是一个接一个地顺序进行。 例如,下面你需要访问三个交易所以获取订单簿信息。 与其按顺序依次访问交易所1,2,3,imap.pool调用是非阻塞的,并直接访问所有三个交易所来获取订单簿信息,只要你一调用就可以。
from pathos.multiprocessing import ProcessingPool as Pool
pool = Pool().imap
self.pool(self.getOrderBook, Exchanges, Tickers)
imap函数来自itertools模块,用于在Python中实现高效的内存使用。map函数返回列表,而imap函数返回一个对象,该对象可以为每个迭代生成值(在Python 2.7中)。下面的代码块将清楚地说明它们之间的区别。
map函数返回的列表可以直接打印输出。
from itertools import *
from math import *
integers = [1,2,3,4,5]
sqr_ints = map(sqrt, integers)
print (sqr_ints)
IMAP返回的是一个对象,该对象被转换为列表并打印出来。
from itertools import *
from math import *
integers = [1,2,3,4,5]
sqr_ints = imap(sqrt, integers)
print list(sqr_ints)
Chunksize参数会将可迭代对象分成指定大小的块(大约相等),每个块都会作为单独的任务提交。
from multiprocessing import Pool
import time
start = time.time()
def get_time():
return int(time.time() - start)
def worker(args):
name, delay = args
print(f'{get_time()}: Job {name} started ({delay} seconds)')
time.sleep(delay)
return f'Job {name} done'
jobs = [
('A', 1),
('B', 2),
('C', 10),
('D', 3),
('E', 4),
('F', 5),
]
if __name__ == '__main__':
with Pool(2) as pool:
for result in pool.map(worker, jobs):
print(f'{get_time()}: {result}')
如果您使用 map
,代码将生成以下输出:
0: Job A started (1 seconds)
0: Job B started (2 seconds)
1: Job C started (10 seconds)
2: Job D started (3 seconds)
5: Job E started (4 seconds)
9: Job F started (5 seconds)
14: Job A done
14: Job B done
14: Job C done
14: Job D done
14: Job E done
14: Job F done
正如您所看到的,所有工作都在第14秒以批量和输入顺序返回,而不管它们实际上何时完成。
如果您将方法更改为imap
,则代码将生成以下输出:
0: Job A started (1 seconds)
0: Job B started (2 seconds)
1: Job C started (10 seconds)
1: Job A done
2: Job D started (3 seconds)
2: Job B done
5: Job E started (4 seconds)
9: Job F started (5 seconds)
11: Job C done
11: Job D done
11: Job E done
14: Job F done
现在完整的代码再次在第14秒完成,但是一些作业(A
,B
)在实际完成时就已经返回了。这种方法仍然保持输入顺序,因此即使(您可以计算出)作业D
和E
在第5秒和第9秒完成,它们也不能提前返回-它们仍然必须等待长时间的作业C
直到第11秒。
如果将方法更改为imap_unordered
,则代码将生成以下输出:
0: Job A started (1 seconds)
0: Job B started (2 seconds)
1: Job C started (10 seconds)
1: Job A done
2: Job D started (3 seconds)
2: Job B done
5: Job E started (4 seconds)
5: Job D done
9: Job F started (5 seconds)
9: Job E done
11: Job C done
14: Job F done
现在所有的作业在完成后立即返回。输入顺序不保留。