NLP | Verwerking van lijsten parallel met execnet

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

In de onderstaande code worden de gehele getallen eenvoudig verdubbeld, elke schone berekening kan worden gedaan. Dit is de module die door execnet moet worden uitgevoerd. Het ontvangt 2 tuples (i, arg), neemt aan dat arg een getal is en stuurt terug (i, arg * 2).

Code:

if __ naam__ = = `__channelexec__` :

voor (i, arg) in kanaal:

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

Te gebruiken deze module om elk item in de lijst te verdubbelen, importeer de plists module en bel plists .map () wi een remote_double module en een lijst met gehele getallen om te verdubbelen.

Code: Gebruik plist


importeer plists, remote_double

plists. kaart (remote_double, bereik ( 10 ))

Uitvoer:

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

De kaart ( ) functie is gedefinieerd in plists.py. Er is een pure module voor nodig, een argumentenlijst en een optionele lijst met twee tupels van (spec, count). Standaard worden de specificaties gebruikt [('popen ', 2)], wat betekent dat de gebruiker twee lokale gateways en kanalen opent. Als deze buizen eenmaal open zijn, kan de gebruiker ze in een itertools-lus plaatsen, die een oneindige iterator creëert die teruggaat naar het begin zodra het einde is bereikt.

Nu kan elk argument als argumenten worden verzonden naar de pijp voor verwerking , en aangezien de kanalen cyclisch zijn, ontvangt elk kanaal een bijna gelijke verdeling van argumenten. Dat is waar Ik kwam — de volgorde waarin de resultaten worden geretourneerd is onbekend, dus i , als de index van elk argument in de lijst, wordt doorgegeven van en naar het kanaal zodat de gebruiker de resultaten in de oorspronkelijke volgorde kan combineren . Wacht vervolgens op de resultaten met de MultiChannel-ontvangstwachtrij en plaats ze in een vooraf ingevulde lijst van dezelfde lengte als de oorspronkelijke argumenten. Nadat u alle verwachte resultaten heeft ontvangen, verlaat u de gateways en retourneert u de resultaten zoals weergegeven in de onderstaande code —

Code:


import itertools, execnet

def map (mod, args, specs = [( `popen` , 2 )]):

gateways = []

kanalen = []

voor spec, count in specificaties:

voor i in bereik (aantal):

gw = execnet.makegateway (spec)

gateways.append (gw )

channels.append (gw.remote_exec (mod))


cyc = itertools.cycle (kanalen)


voor i, arg in opsommen (args):

kanaal = volgende (cyc )

channel.send ((i, arg))

mch = execnet.MultiChannel (kanalen)

wachtrij = mch.make_receive_queue ()

l = len (args)

# maakt een lijst met lengte l,

# waarbij elk element Geen is

resultaten = [ Geen ] * l

voor i in bereik (l):

kanaal, (i, resultaat) = queue.get ()

resultaten [i] = resultaat

voor gw in gateways:

gw.exit ()

return resultaten

Code: Verhoog de parallellisatie door de specificatie te wijzigen


lijsten. map (remote_double, bereik ( 10 ), [( `popen` , 4 )])

Uitvoer:

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

Niet meer parallellisatie betekent echter noodzakelijkerwijs snellere verwerking. Het hangt af van de beschikbare middelen, en hoe meer gateways en kanalen er worden geopend, hoe meer overhead. Idealiter zou er één gateway en kanaal per CPU-kern moeten zijn om het gebruik van bronnen te maximaliseren. Gebruik plists.map () met elke schone module zolang deze 2 tupels ontvangt en terugstuurt, waarbij i het eerste element is. Dit patroon is vooral handig als er veel getallen moeten worden verwerkt om ze zo snel mogelijk te verwerken.