簡體   English   中英

如何將生成器用作具有多處理映射功能的可迭代對象

[英]How to use a generator as an iterable with Multiprocessing map function

當我使用生成器作為 multiprocessing.Pool.map 函數的可迭代參數時:

pool.map(func, iterable=(x for x in range(10)))

似乎在func之前生成器已完全耗盡。

我想產生每個項目並將其傳遞給每個進程,謝謝

multiprocessing.map在處理之前將沒有__len__方法的迭代轉換為列表。 這樣做是為了幫助計算塊大小,池使用它來對工作參數進行分組並減少調度作業的往返成本。 這不是最優的,尤其是當 chunksize 為 1 時,但由於map必須以一種或另一種方式耗盡迭代器,所以它通常不是一個重要的問題。

相關代碼在pool.py 注意它對len使用:

def _map_async(self, func, iterable, mapper, chunksize=None, callback=None,
        error_callback=None):
    '''
    Helper function to implement map, starmap and their async counterparts.
    '''
    if self._state != RUN:
        raise ValueError("Pool not running")
    if not hasattr(iterable, '__len__'):
        iterable = list(iterable)

    if chunksize is None:
        chunksize, extra = divmod(len(iterable), len(self._pool) * 4)
        if extra:
            chunksize += 1
    if len(iterable) == 0:
        chunksize = 0

唉,這不是很好的定義。 這是我在 Python 3.6.1 下運行的測試用例:

import multiprocessing as mp

def e(i):
    if i % 1000000 == 0:
        print(i)

if __name__ == '__main__':
    p = mp.Pool()
    def g():
        for i in range(100000000):
            yield i
        print("generator done")
    r = p.map(e, g())
    p.close()
    p.join()

您看到的第一件事是“生成器完成”消息,並且峰值內存使用量高得不合理(正如您懷疑的那樣,這正是因為生成器在執行任何工作之前已耗盡)。

但是,像這樣替換map()調用:

r = list(p.imap(e, g()))

現在內存使用量仍然很小,並且“生成器完成”出現在輸出端。

但是,您不會等待足夠長的時間才能看到它,因為它非常慢:-( imap()不僅將該可迭代對象視為可迭代對象,而且一次僅有效地跨進程邊界傳遞 1 個項目。為了恢復速度,這有效:

r = list(p.imap(e, g(), chunksize=10000))

在現實生活中,我更有可能迭代imap() (或imap_unordered() )結果,而不是將其強制放入列表中,然后內存使用量仍然很小,用於循環結果。

以 Tim Peters 的回答為基礎,這里有一個 jupyter notebook 展示了 imap 和 chunksize 之間的相互作用:

https://gist.github.com/shadiakiki1986/273b3529d3ff7afe2f2cac7b5ac96fe2

它有2個例子:

示例 1 使用 chunksize=1 並具有以下執行:

    On CPU 1, execute item 1 from generator
    On CPU 2, execute item 2 from generator
    When CPU 1 done with item 1, execute item 3 from generator
    When CPU 2 done with item 2, execute item 4 from generator
    etc

示例 2 的 chunksize=3 執行以下操作

    On CPU 1, execute items 1-3 from generator
    On CPU 2, execute items 4-6 from generator
    When CPU 1 done with items 1-3, execute on 7-9
    When CPU 2 done with items 4-6, execute on 10

請注意,在示例 2 中,第 10 項在 CPU 2 上執行,然后在 CPU 1 上執行第 8 項和第 9 項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM