Parallellisering av en "för" -slinga i Python för förbättrad prestanda innebär att distribuera slingans iterationer över flera processorkärnor. Flera tillvägagångssätt finns, var och en med sina egna styrkor och svagheter:
1. Använda `multiprocessing ': Detta är i allmänhet det bästa tillvägagångssättet för CPU-bundna uppgifter (uppgifter som tillbringar större delen av sin tid på att göra beräkningar). Det skapar flera processer, var och en kör en del av slingan.
`` `python
importera multiprocessing
DEF Process_Item (artikel):
"" "Funktionen som ska tillämpas på varje objekt i slingan." "" "
# Din kod för att behandla ett enda objekt går här
resultat =artikel * 2 # Exempel:Dubbel objektet
avkastningsresultat
om __name__ =='__main__':# viktigt för Windows -kompatibilitet
Objekt =lista (intervall (1000)) # Exempel Lista över objekt
med multiprocessing.pool (processer =multiprocessing.cpu_count ()) som pool:
resultat =pool.map (process_item, objekt)
utskrift (resultat)
`` `
* `multiprocessing.pool`: Skapar en pool av arbetstagarprocesser. `multiprocessing.cpu_count ()` bestämmer det optimala antalet processer baserat på ditt systems kärnor. Du kan justera detta nummer om det behövs.
* `pool.map`: Tillämpar funktionen "Process_item" på varje objekt i "artiklarna" iterable. Det hanterar att distribuera arbetet och samla in resultaten effektivt.
* `om __Name__ =='__main __':`: Detta är avgörande, särskilt på Windows, för att förhindra skapandet av flera processer rekursivt.
2. Använda `concurrent.futures`: Ger ett gränssnitt på högre nivå till multiprocessing och gängning, vilket erbjuder mer flexibilitet.
`` `python
importera samtidiga.
DEF Process_Item (artikel):
"" "Funktionen som ska tillämpas på varje objekt i slingan." "" "
# Din kod för att behandla ett enda objekt går här
resultat =artikel * 2 # Exempel:Dubbel objektet
avkastningsresultat
om __name__ =='__main__':
objekt =lista (intervall (1000))
med samtidiga.futures.processpoolExecutor () som exekutiv:
resultat =lista (exekutor.map (process_item, objekt)))
utskrift (resultat)
`` `
Detta liknar mycket "multiprocessing", men anses ofta vara mer pytonisk och lättare att använda. `ProcessPoolExecutor 'använder processer, medan` ThreadPoolExecutor' använder trådar (bättre för I/O-bundna uppgifter).
3. Använda `gängning '(för I/O-bundna uppgifter): Om din slinga innebär mycket väntan (t.ex. nätverksförfrågningar, fil I/O), kan trådar vara mer effektiva än processer. Emellertid begränsar det globala tolklåset (GIL) i CPython verklig parallellism för CPU-bundna uppgifter inom trådar.
`` `python
importtrådning
def process_item (objekt, resultat):
"" "Funktionen som ska tillämpas på varje objekt i slingan." "" "
# Din kod för att behandla ett enda objekt går här
resultat =artikel * 2 # Exempel:Dubbel objektet
resultat.Append (resultat)
om __name__ =='__main__':
objekt =lista (intervall (1000))
resultat =[]
trådar =[]
För objekt i artiklar:
tråd =tråd. Thread (mål =process_item, args =(objekt, resultat))
trådar.Append (tråd)
tråd.start ()
För tråd i trådar:
tråd.join ()
utskrift (resultat)
`` `
Detta exempel är mer komplicerat eftersom du måste hantera trådar och en delad resultatlista uttryckligen. `Samtidig.Futures.ThreadPoolExecutor` förenklar detta betydligt.
Att välja rätt metod:
* cpu-bundet: Använd `multiprocessing` eller` samtidig.futures.processpoolexecutor`. Processer kringgår GIL och möjliggör verklig parallellism.
* i/o-bundet: Använd `samtidig.futures.ThreadPoolExecutor`. Trådar är lättare vikt än processer, och omkopplingens omkoppling är lägre. Om I/O är mycket långsamt kan detta förbättra prestandan även med GIL.
* blandat: Om din slinga har både CPU-bundna och I/O-bundna delar, kan du behöva ett mer sofistikerat tillvägagångssätt, potentiellt kombinera trådar och processer eller använda asynkron programmering (t.ex. `asyncio ').
Viktiga överväganden:
* overhead: Att skapa och hantera processer eller trådar introducerar omkostnader. Parallellisering ger endast en fördel om arbetet som gjorts per artikel är tillräckligt betydande för att överväga denna omkostnad.
* Datadelning: Att dela data mellan processer är mer komplexa än att dela data mellan trådar. Överväg att använda köer eller andra kommunikationsmekanismer mellan processer vid behov.
* felsökning: Felsökning av parallellkod kan vara utmanande. Börja med små exempel och öka gradvis komplexiteten.
Kom ihåg att profilera din kod för att mäta prestandaförbättringen efter parallellisering. Det är möjligt att parallellisering inte ger någon betydande fördel, eller till och med bromsar saker, om omkostnaden är för hög eller om uppgiften inte är lämplig för parallellisering.