Python Incrementa un número en una función llamada con multiprocessing.pool.map()

Estoy tratando de incrementar un número secuencialmente en una función a la que llama multiprocessing.pool.map(). Cuando ejecuto el siguiente código, obtengo el número incrementado la misma cantidad de veces que hay grupos para cada número.

import time
import multiprocessing
import decimal
import random

lists = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h','i', 'j', 'k']
def thefunction(listi):
    global number
    number += 1
    time.sleep(decimal.Decimal(random.random()))
    print time.strftime('%H:%M:%S'), number, listi

number = 0
pool = multiprocessing.Pool(4)
pool.map(thefunction, lists)
print number

Los resultados se imprimen así

01:01:28 1 b
01:01:28 2 e
01:01:28 1 a
01:01:28 1 c
01:01:28 1 d
01:01:28 2 h
01:01:29 2 i
01:01:29 2 g
01:01:29 3 f
01:01:29 3 j
01:01:29 3 k
0

¿Cómo puedo incrementar el número correctamente?

(time.sleep(decimal.Decimal(random.random())) solo se agregó para detener la impresión del script en la misma línea)

preguntado el 25 de agosto de 12 a las 01:08

¿Has probado lockmientras estás accediendo al número? -

2 Respuestas

La razón por la que el ejemplo no funciona es que varias instancias del contador se crean e incrementan por separado.

Debe crear un contador y un bloqueo compartidos que se inicialicen adecuadamente para cada proceso que se inicie:

import time
from multiprocessing import Pool, Value, Lock
import decimal
import random

number = Value('i', 0)
lock = Lock()
lists = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h','i', 'j', 'k']

def thefunction(listi):
    time.sleep(decimal.Decimal(random.random()))
    with lock:
        number.value += 1
        print time.strftime('%H:%M:%S'), number.value, listi

def initializer(*args):
    global number, lock
    number, lock = args

pool = Pool(4, initializer, (number, lock))
pool.map(thefunction, lists)
print number.value

Respondido 25 ago 12, 16:08

¿Por qué estás envolviendo todo en un multiprocessing.Lock? con esto, la parte "paralelizable" (time.sleep()) siempre se ejecuta secuencialmente. - Eliminación de negación única

@TokenMacGuy. Vaya, sí, error tonto de copiar y pegar. Arreglado ahora. Gracias. - ehumoro

Gracias esto es perfecto. Más complicado de lo que esperaba jajaja, pero justo lo que estaba buscando. - James

Impresionante, lo que estaba buscando la última hora! - Jean-François T.

Probablemente quieras un multiprocessing.Value por el estado compartido.

O más bien, eso hará lo que tú contacta pero puede que no sea lo que realmente quieres; El estado compartido en un contexto paralelo suele ser un signo de un defecto de diseño. Una cosa que podría hacer en su lugar es hacer que cada proceso realice un seguimiento de cuántos elementos ha procesado y devuelva que contar al padre; el padre puede sumar el número de trabajos completados por cada uno para determinar cuánto trabajo se ha realizado hasta este punto.

¿Cuál es la razón por la que está tratando de contar a través de los límites del proceso?

Respondido 25 ago 12, 01:08

Tenía la sensación de que mi suerte estaba a punto de agotarse y esta parte iba a ser demasiado complicada. No sé cómo interactuar con los procesos en ejecución o pasar valores como sugieres, pero echaré un vistazo a multiprocessing.value. Gracias. Este código es una versión simplificada de un script en el que la función tarda entre 10 y 30 minutos en completarse y ejecuta una lista de unos 40 elementos. Solo estoy tratando de medir qué tan avanzado está el script en la lista para poder adivinar cuánto tiempo llevará completarlo. - James

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.