web-dev-qa-db-fra.com

Existe-t-il une carte parallèle simple basée sur des processus pour python?

Je recherche une carte parallèle simple basée sur des processus pour python, c'est-à-dire une fonction

parmap(function,[data])

cela fonctionnerait sur chaque élément de [data] sur un processus différent (enfin, sur un noyau différent, mais autant que je sache, le seul moyen d'exécuter des tâches sur différents cœurs en python est de démarrer plusieurs interpréteurs) et de renvoyer une liste de résultats .

Est-ce que quelque chose comme ça existe? Je voudrais quelque chose simple, donc un module simple serait Nice. Bien sûr, si cela n'existe pas, je me contenterai d'une grande bibliothèque: - /

56
static_rtti

Il me semble que ce dont vous avez besoin est la méthode map en multitraitement.Pool () :

map (func, iterable [ chunksize])

A parallel equivalent of the map() built-in function (it supports only
one iterable argument though). It blocks till the result is ready.

This method chops the iterable into a number of chunks which it submits to the 
process pool as separate tasks. The (approximate) size of these chunks can be 
specified by setting chunksize to a positive integ

Par exemple, si vous voulez mapper cette fonction:

def f(x):
    return x**2

pour aller dans la plage (10), vous pouvez le faire en utilisant la fonction map () intégrée:

map(f, range(10))

ou en utilisant la méthode map () d'un objet multiprocessing.Pool ():

import multiprocessing
pool = multiprocessing.Pool()
print pool.map(f, range(10))
96
Flávio Amieiro

Je sais que ceci est un ancien post, mais juste au cas où, j’ai écrit un outil pour rendre ce super, super facile appelé parmapper (j’appelle en réalité parmap dans mon utilisation mais le nom a été pris).

Il gère une grande partie de la configuration et de la déconstruction des processus et ajoute des tonnes de fonctionnalités. En ordre d'importance

  • Peut prendre lambda et d'autres fonctions non piquables
  • Peut appliquer starmap et d’autres méthodes d’appel similaires pour faciliter son utilisation directe.
  • Peut se répartir entre les deux threads et/ou processus
  • Inclut des fonctionnalités telles que des barres de progression

Cela n'engendre qu'un faible coût, mais pour la plupart des utilisations, c'est négligeable.

J'espère que tu trouves cela utile.

(Remarque: comme map dans Python 3+, il retourne un itératif. Par conséquent, si vous vous attendez à ce que tous les résultats le traversent immédiatement, utilisez list().)

1
Justin Winokur

Cela peut être fait élégamment avec Ray , un système qui vous permet de paralléliser et de distribuer facilement votre code Python.

Pour paralléliser votre exemple, vous devez définir votre fonction de carte avec le décorateur @ray.remote, puis l’appeler avec .remote. Cela garantira que chaque instance de la fonction distante sera exécutée dans un processus différent.

import time
import ray

ray.init()

# Define the function you want to apply map on, as remote function. 
@ray.remote
def f(x):
    # Do some work...
    time.sleep(1)
    return x*x

# Define a helper parmap(f, list) function.
# This function executes a copy of f() on each element in "list".
# Each copy of f() runs in a different process.
# Note f.remote(x) returns a future of its result (i.e., 
# an identifier of the result) rather than the result itself.  
def parmap(f, list):
    return [f.remote(x) for x in list]

# Call parmap() on a list consisting of first 5 integers.
result_ids = parmap(f, range(1, 6))

# Get the results
results = ray.get(result_ids)
print(results)

Cela va imprimer:

[1, 4, 9, 16, 25]

et il se terminera approximativement par len(list)/p (arrondi à l'entier le plus proche), où p est le nombre de cœurs de votre machine. En supposant une machine à 2 cœurs, notre exemple s’exécutera en 5/2 arrondi, c’est-à-dire en environ 3 sec.

L'utilisation de Ray sur le module multitraitement présente de nombreux avantages. En particulier, le code same s'exécutera sur une seule machine ainsi que sur un cluster de machines. Pour plus d’avantages de Ray, voir cet article connexe .

0
Ion Stoica

Pour ceux qui recherchent l’équivalent Python de mclapply () de R, voici mon implémentation. C'est une amélioration des deux exemples suivants:

Il peut être appliqué aux fonctions de mappage avec un ou plusieurs arguments.

import numpy as np, pandas as pd
from scipy import sparse
import functools, multiprocessing
from multiprocessing import Pool

num_cores = multiprocessing.cpu_count()

def parallelize_dataframe(df, func, U=None, V=None):

    #blockSize = 5000
    num_partitions = 5 # int( np.ceil(df.shape[0]*(1.0/blockSize)) )
    blocks = np.array_split(df, num_partitions)

    pool = Pool(num_cores)
    if V is not None and U is not None:
        # apply func with multiple arguments to dataframe (i.e. involves multiple columns)
        df = pd.concat(pool.map(functools.partial(func, U=U, V=V), blocks))
    else:
        # apply func with one argument to dataframe (i.e. involves single column)
        df = pd.concat(pool.map(func, blocks))

    pool.close()
    pool.join()

    return df

def square(x):
    return x**2

def test_func(data):
    print("Process working on: ", data.shape)
    data["squareV"] = data["testV"].apply(square)
    return data

def vecProd(row, U, V):
    return np.sum( np.multiply(U[int(row["obsI"]),:], V[int(row["obsJ"]),:]) )

def mProd_func(data, U, V):
    data["predV"] = data.apply( lambda row: vecProd(row, U, V), axis=1 )
    return data

def generate_simulated_data():

    N, D, nnz, K = [302, 184, 5000, 5]
    I = np.random.choice(N, size=nnz, replace=True)
    J = np.random.choice(D, size=nnz, replace=True)
    vals = np.random.sample(nnz)

    sparseY = sparse.csc_matrix((vals, (I, J)), shape=[N, D])

    # Generate parameters U and V which could be used to reconstruct the matrix Y
    U = np.random.sample(N*K).reshape([N,K])
    V = np.random.sample(D*K).reshape([D,K])

    return sparseY, U, V

def main():
    Y, U, V = generate_simulated_data()

    # find row, column indices and obvseved values for sparse matrix Y
    (testI, testJ, testV) = sparse.find(Y)

    colNames = ["obsI", "obsJ", "testV", "predV", "squareV"]
    dtypes = {"obsI":int, "obsJ":int, "testV":float, "predV":float, "squareV": float}

    obsValDF = pd.DataFrame(np.zeros((len(testV), len(colNames))), columns=colNames)
    obsValDF["obsI"] = testI
    obsValDF["obsJ"] = testJ
    obsValDF["testV"] = testV
    obsValDF = obsValDF.astype(dtype=dtypes)

    print("Y.shape: {!s}, #obsVals: {}, obsValDF.shape: {!s}".format(Y.shape, len(testV), obsValDF.shape))

    # calculate the square of testVals    
    obsValDF = parallelize_dataframe(obsValDF, test_func)

    # reconstruct prediction of testVals using parameters U and V
    obsValDF = parallelize_dataframe(obsValDF, mProd_func, U, V)

    print("obsValDF.shape after reconstruction: {!s}".format(obsValDF.shape))
    print("First 5 elements of obsValDF:\n", obsValDF.iloc[:5,:])

if __== '__main__':
    main()
0
Good Will