web-dev-qa-db-fra.com

Python 3: Pool conserve-t-il l'ordre d'origine des données transmises à la carte?

J'ai écrit un petit script pour répartir la charge de travail entre 4 threads et pour tester si les résultats restent ordonnés (par rapport à l'ordre de l'entrée):

from multiprocessing import Pool
import numpy as np
import time
import random


rows = 16
columns = 1000000

vals = np.arange(rows * columns, dtype=np.int32).reshape(rows, columns)

def worker(arr):
    time.sleep(random.random())        # let the process sleep a random
    for idx in np.ndindex(arr.shape):  # amount of time to ensure that
        arr[idx] += 1                  # the processes finish at different
                                       # time steps
    return arr

# create the threadpool
with Pool(4) as p:
    # schedule one map/worker for each row in the original data
    q = p.map(worker, [row for row in vals])

for idx, row in enumerate(q):
    print("[{:0>2}]: {: >8} - {: >8}".format(idx, row[0], row[-1]))

Pour moi, cela se traduit toujours par:

[00]:        1 -  1000000
[01]:  1000001 -  2000000
[02]:  2000001 -  3000000
[03]:  3000001 -  4000000
[04]:  4000001 -  5000000
[05]:  5000001 -  6000000
[06]:  6000001 -  7000000
[07]:  7000001 -  8000000
[08]:  8000001 -  9000000
[09]:  9000001 - 10000000
[10]: 10000001 - 11000000
[11]: 11000001 - 12000000
[12]: 12000001 - 13000000
[13]: 13000001 - 14000000
[14]: 14000001 - 15000000
[15]: 15000001 - 16000000

Question: Donc, Pool conserve-t-il vraiment l'ordre de l'entrée d'origine lors du stockage des résultats de chaque fonction map dans q?

Sidenote: Je pose cette question, car j'ai besoin d'un moyen simple de paralléliser le travail sur plusieurs travailleurs. Dans certains cas, la commande n'est pas pertinente. Cependant, dans certains cas, les résultats (comme dans q) doivent être renvoyés dans l'ordre d'origine, car j'utilise une fonction de réduction supplémentaire qui s'appuie sur les données ordonnées.

Performance: Sur ma machine, cette opération est environ 4 fois plus rapide (comme prévu, car j'ai 4 cœurs) que l'exécution normale sur un seul processus. De plus, les 4 cœurs sont à 100% utilisés pendant l'exécution.

23
daniel451

Pool.map les résultats sont ordonnés. Si vous avez besoin de commande, c'est parfait; si vous ne le faites pas, Pool.imap_unordered peut être une optimisation utile.

Notez que tandis que l'ordre dans lequel vous recevez les résultats de Pool.map est fixe, l'ordre dans lequel ils sont calculés est arbitraire.

32
user2357112

La documentation le facture comme "équivalent parallèle de la fonction intégrée map()" . Puisque map est garanti pour préserver l'ordre, multiprocessing.Pool.map fait aussi cette garantie.

9
mgilson