NLP | Procesamiento de listas en paralelo con execnet

| | | | | | | | | | | | | | | | | | | |

En el siguiente código, los números enteros simplemente se duplican, se puede realizar cualquier cálculo limpio. Este es el módulo que ejecutará execnet. Recibe 2 tuplas (i, arg), asume que arg es un número y devuelve (i, arg * 2).

Código:

if __ nombre__ = = `__channelexec__` :

para < /código> (i, arg) en canal:

canal.send ((i, arg * 2 ))

Para usar este módulo para duplicar cada elemento de la lista, importe el módulo plists y llame a plists .map () wi un módulo remote_double y una lista de enteros para duplicar.

Código: usando plist


import plists, remote_double

plists. mapa (remote_double, rango ( 10 ))

Salida:

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 

El mapa ( ) La función se define en plists.py. Toma un módulo puro, una lista de argumentos y una lista opcional de dos tuplas de (especificación, conteo). De forma predeterminada, se usan las especificaciones [(' popen ', 2)], lo que significa que el usuario abrirá dos puertas de enlace y canales locales. Una vez que estos conductos están abiertos, el usuario puede colocarlos en un ciclo de itertools, lo que crea un iterador infinito que vuelve al principio tan pronto como llega al final.

Ahora cada argumento se puede enviar como argumentos a la canalización para su procesamiento, y dado que los canales son cíclicos, cada canal recibe una distribución de argumentos casi igual. Ahí es donde yo entré — se desconoce el orden en que se devuelven los resultados, por lo que i , como el índice de cada argumento de la lista, se pasa hacia y desde el canal para que el usuario pueda combinar los resultados en el orden original. . Luego, espere los resultados con la cola de recepción MultiChannel e insértelos en una lista rellenada previamente de la misma longitud que los argumentos originales. Después de obtener todos los resultados esperados, salga de las puertas de enlace y devuelva los resultados como se muestra en el siguiente código —

Código:


importar itertools, execnet

def mapa (mod, argumentos, especificaciones = [( `abrir` , 2 )]):

puertas de enlace < código clase ="palabra clave"> = []

canales = []

< clase de código ="palabra clave"> para especificación, recuento en especificaciones:

para i en rango (recuento):

gw < clase de código = "palabra clave"> = execnet.makegateway (especificación)

gateways.append (gw )

canales.append (gw.remote_exec (mod))


cyc = itertools.cycle (canales)


< clase de código = "espacios indefinidos"> para i, arg en < /código> enumerar (argumentos):

canal = siguiente (cyc )

channel.send ((i, arg))

mch = execnet.MultiChannel (canales)

cola = mch.make_receive_queue ()

l = len (argumentos)

# crea una lista de longitud l,

# donde cada elemento es Ninguno

resultados = [ Ninguno ] * l

for i en rango (l):

canal, (i, resultado) = cola.get ()

resultados [i] = resultado

para gw en puertas de enlace:

gw.exit ()

return resultados

Código: Aumente la paralelización cambiando la especificación


plistas. mapa (remote_double, rango ( 10 ), [( `popen` , 4 )])

Salida:

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 

Sin embargo, no más paralelización significa necesariamente un procesamiento más rápido. Depende de los recursos disponibles, y cuantas más puertas de enlace y canales se abran, más gastos generales. Idealmente, debería haber una puerta de enlace y un canal por núcleo de CPU para maximizar la utilización de recursos. Use plists.map () con cualquier módulo limpio siempre que reciba y envíe 2 tuplas, donde i es el primer elemento. Este patrón es más útil cuando hay muchos números que deben procesarse para procesarlos lo más rápido posible.