Python: ¿Por qué diferentes hilos obtienen su propia serie de valores de un generador?

Estoy aprendiendo multiproceso en Python. Quiero saber cómo proporcionar datos a varios subprocesos utilizando generadores. Esto es lo que escribí:

import threading data = [i for i in xrange(100)] def generator(): for i in data: yield i class CountThread(threading.Thread): def __init__(self, name): threading.Thread.__init__(self) self.name = name def run(self): for i in generator(): print '{0} {1}'.format(self.name, i) a = CountThread('a') b = CountThread('b') a.start() b.start() 

Pensé que la lista solo sería iterada por una vez. Pero parece que cada hilo está interactuando a través de la lista de forma independiente.

salida:

 a 0 a 1 a 2 b 0 a 3 a 4 b 1 b 2 a 5 a 6 a 7 a 8 a 9 b 3 b 4 b 5 b 6 b 7 b 8 ... (200 lines) 

¿Cuál es la razón subyacente de esto? ¿Cómo puedo reescribir el progtwig para que los valores de la lista solo se impriman una vez?

Usted crea una instancia de un nuevo generador en cada hilo en la función de run con esto:

 for i in generator(): 

Cada llamada de generator devuelve una nueva instancia de generador:

 >>> data = [i for i in xrange(10)] >>> a, b = generator(), generator() >>> id(a), id(b) (37528032, 37527952) 

Aquí a y b tienen diferentes identificaciones, y generan resultados idénticos incluso sin subprocesos:

 >>> list(a), list(b) ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

Sin embargo, tenga en cuenta que los generadores no son seguros para subprocesos, es difícil usarlos en aplicaciones de subprocesos. ValueError: generator already executing preocuparse por el locking, vea el ejemplo , o obtendrá un ValueError: generator already executing error de vez en cuando. Alternativamente, puede usar Queue.Queue para la comunicación de subprocesos.

¿Puedes usar la clase de cola de Python? Creo que es hilo seguro. Básicamente, puedes usar tu generador para llenar la cola y luego sacar cada hilo de él.

 #!/usr/bin/python import Queue import threading queueOfNumbers = Queue.Queue() data = [i for i in xrange(100)] def generator(): for i in data: yield i class CountThread(threading.Thread): def __init__(self, name, queue): threading.Thread.__init__(self) self.name = name self.queue = queue def run(self): i = self.queue.get() print '%s %s' % (self.name, i) a = CountThread('a', queueOfNumbers) b = CountThread('b', queueOfNumbers) a.start() b.start() for num in generator(): queueOfNumbers.put(num) queueOfNumbers.join() 

http://www.ibm.com/developerworks/aix/library/au-threadingpython/