() translation by (you can also view the original English article)
El paquete de multiprocesamiento apoya los procesos de desove utilizando una API similar al módulo threading. También ofrece concurrencia local y remota. Este tutorial explicará multiprocesamiento en Python y cómo utilizar multiproceso para comunicarse entre procesos y realizar la sincronización entre procesos, así como registro.
Introducción a Multiprocesador
Multiprocesamiento funciona creando un objeto del process
y luego llamando a su método start()
como se muestra a continuación.
1 |
from multiprocessing import Process |
2 |
|
3 |
|
4 |
def greeting(): |
5 |
print 'hello world' |
6 |
|
7 |
if __name__ == '__main__': |
8 |
p = Process(target=greeting) |
9 |
p.start() |
10 |
p.join() |
En el código de ejemplo anterior, primero importamos la clase de proceso y luego instanciar el objeto del proceso con la función de saludo que queremos ejecutar.
Luego contamos el proceso para comenzar a usar el método start()
, y finalmente terminamos el proceso con el método join()
.
Además, también puede pasar argumentos a la función proporcionando los argumentos
argumento de palabra clave así:
1 |
from multiprocessing import Process |
2 |
|
3 |
|
4 |
def greeting(name): |
5 |
print 'hello' + " " + name |
6 |
|
7 |
if __name__ == '__main__': |
8 |
p = Process(target=greeting, args=('world',)) |
9 |
p.start() |
10 |
p.join() |
Ejemplo
Veamos un ejemplo más detallado que cubre todos los conceptos que hemos discutido anteriormente.
En este ejemplo, vamos a crear un proceso que calcula el cuadrado de números e imprime los resultados en la consola.
1 |
from multiprocessing import Process |
2 |
|
3 |
|
4 |
def square(x): |
5 |
|
6 |
for x in numbers: |
7 |
print('%s squared is %s' % (x, x**2)) |
8 |
|
9 |
if __name__ == '__main__': |
10 |
numbers = [43, 50, 5, 98, 34, 35] |
11 |
|
12 |
p = Process(target=square, args=('x',)) |
13 |
p.start() |
14 |
p.join |
15 |
print "Done" |
16 |
|
17 |
|
18 |
#result
|
19 |
Done
|
20 |
43 squared is 1849 |
21 |
50 squared is 2500 |
22 |
5 squared is 25 |
23 |
98 squared is 9604 |
24 |
34 squared is 1156 |
25 |
35 squared is 1225 |
26 |
También puede crear más de un proceso al mismo tiempo, como se muestra en el ejemplo siguiente, en que el proceso p1 obtiene los resultados de los números cuadrados, mientras que el segundo proceso p2 comprueba si los números dados son incluso.
1 |
from multiprocessing import Process |
2 |
|
3 |
|
4 |
def square(x): |
5 |
|
6 |
for x in numbers: |
7 |
print('%s squared is %s' % (x, x**2)) |
8 |
|
9 |
|
10 |
def is_even(x): |
11 |
|
12 |
for x in numbers: |
13 |
if x % 2 == 0: |
14 |
print('%s is an even number ' % (x)) |
15 |
|
16 |
|
17 |
if __name__ == '__main__': |
18 |
numbers = [43, 50, 5, 98, 34, 35] |
19 |
|
20 |
p1 = Process(target=square, args=('x',)) |
21 |
p2 = Process(target=is_even, args=('x',)) |
22 |
|
23 |
p1.start() |
24 |
p2.start() |
25 |
|
26 |
p1.join() |
27 |
p2.join() |
28 |
|
29 |
print "Done" |
30 |
|
31 |
#result
|
32 |
|
33 |
43 squared is 1849 |
34 |
50 squared is 2500 |
35 |
5 squared is 25 |
36 |
98 squared is 9604 |
37 |
34 squared is 1156 |
38 |
35 squared is 1225 |
39 |
50 is an even number |
40 |
98 is an even number |
41 |
34 is an even number |
42 |
Done
|
43 |
Comunicación Entre Procesos
Multiprocesamiento admite dos tipos de canales de comunicación entre procesos:
- Tubos
- Colas de trabajos
Colas de Trabajos
Objetos de cola
se utilizan para pasar datos entre procesos. Puede almacenar cualquier objeto de Python capaz de salmuera, y se pueden utilizar como se muestra en el ejemplo siguiente:
1 |
import multiprocessing |
2 |
|
3 |
|
4 |
def is_even(numbers, q): |
5 |
for n in numbers: |
6 |
if n % 2 == 0: |
7 |
q.put(n) |
8 |
|
9 |
if __name__ == "__main__": |
10 |
|
11 |
q = multiprocessing.Queue() |
12 |
p = multiprocessing.Process(target=is_even, args=(range(20), q)) |
13 |
|
14 |
p.start() |
15 |
p.join() |
16 |
|
17 |
while q: |
18 |
print(q.get()) |
En el ejemplo anterior, primero creamos una función que comprueba si un número está incluso y luego pone el resultado en el final de la cola. Luego crear una instancia de un objeto de cola y un objeto del proceso y comenzar el proceso.
Finalmente, comprueba si la cola está vacía, y si no, obtenemos los valores de la parte delantera de la cola e imprimir en la consola.
Hemos demostrado cómo compartir datos entre dos procesos mediante una cola, y el resultado es como se muestra a continuación.
1 |
# result
|
2 |
|
3 |
0 |
4 |
2 |
5 |
4 |
6 |
6 |
7 |
8 |
8 |
10 |
9 |
12 |
10 |
14 |
11 |
16 |
12 |
18 |
También es importante tener en cuenta que Python dispone de un módulo de cola que vive en el módulo de proceso y se utiliza para compartir datos entre subprocesos, a diferencia de la cola de multiprocesamiento que vive en la memoria compartida y se utiliza para compartir datos entre procesos.
Tubos
Tubos de multiprocesamiento se utilizan principalmente para comunicación entre procesos. Es tan simple como:
1 |
from multiprocessing import Process, Pipe |
2 |
|
3 |
def f(conn): |
4 |
conn.send(['hello world']) |
5 |
conn.close() |
6 |
|
7 |
if __name__ == '__main__': |
8 |
parent_conn, child_conn = Pipe() |
9 |
p = Process(target=f, args=(child_conn,)) |
10 |
p.start() |
11 |
print parent_conn.recv() |
12 |
p.join() |
Pipe()
devuelve dos objetos de conexión que representan los dos extremos de la tubería. Cada objeto de conexión tiene métodos send()
y recv()
. Aquí creamos un proceso que imprime el Hola mundo
de cadena y entonces comparte los datos.
Resultado
1 |
# result
|
2 |
|
3 |
['hello world'] |
Locks
Lock
asegurándose de sólo un proceso se ejecuta en un momento, por lo tanto, bloquea otros procesos de ejecución de código similar. Esto permite que el proceso a realizar, y sólo entonces se puede lanzar la cerradura.
El siguiente ejemplo muestra un uso muy sencillo el método de bloqueo.
1 |
from multiprocessing import Process, Lock |
2 |
|
3 |
|
4 |
def greeting(l, i): |
5 |
l.acquire() |
6 |
print 'hello', i |
7 |
l.release() |
8 |
|
9 |
if __name__ == '__main__': |
10 |
lock = Lock() |
11 |
names = ['Alex', 'sam', 'Bernard', 'Patrick', 'Jude', 'Williams'] |
12 |
|
13 |
for name in names: |
14 |
Process(target=greeting, args=(lock, name)).start() |
15 |
|
16 |
|
17 |
#result
|
18 |
hello Alex |
19 |
hello sam |
20 |
hello Bernard |
21 |
hello Patrick |
22 |
hello Jude |
23 |
hello Williams |
24 |
En este código, importar primero el método de bloqueo, adquirirla, ejecutar la función de imprimir y luego suéltelo
Registro
El módulo de multiprocesamiento también proporciona soporte para el registro, aunque el paquete de registro no utiliza bloqueos para mensajes entre procesos pueden ser mezclado para arriba durante la ejecución.
Uso de registro es tan simple como:
1 |
import multiprocessing, logging |
2 |
logger = multiprocessing.log_to_stderr() |
3 |
logger.setLevel(logging.INFO) |
4 |
logger.warning('Error has occurred') |
Aquí en primer lugar importamos la tala y los módulos de multiprocesamiento, y luego definir el método de multiprocessing.log_to_stderr()
, que realiza una llamada a get_logger()
así como la adición de un controlador que envía salida a sys.stderr
. Por último, establecemos el nivel de registrador y el mensaje que queremos transmitir.
Conclusión
Este tutorial ha cubierto lo que es necesario empezar con multiprocesamiento en Python. Multiprocesamiento supera el problema de GIL (bloqueo Global del intérprete) ya que aprovecha el uso de subprocesos en lugar de hilos.
Hay mucho más en la documentación de Python que no está cubierta en este tutorial, así que siéntete libre de visitar la documentación de Python multiprocesamiento y utilizar toda la potencia de este módulo.