Python biedt verschillende manieren om for-loops te parallelliseren, elk met zijn eigen sterke en zwakke punten. De beste keuze hangt af van de aard van het werk binnen de lus en de beschikbare hardware.
1. `multiverwerking`: Dit is over het algemeen de beste keuze voor CPU-gebonden taken (taken die het grootste deel van hun tijd aan berekeningen besteden). Het creëert meerdere processen, elk met zijn eigen tolk, waardoor echt parallellisme mogelijk is en de Global Interpreter Lock (GIL) wordt omzeild die threading in CPython beperkt.
```python
multiprocessing importeren
def proces_item(item):
"""De functie die parallel moet worden uitgevoerd."""
# Hier vindt u uw code om één item te verwerken.
resultaat =item * 2 # Voorbeeld:verdubbel het item
resultaat terug
if __name__ =='__main__':# Belangrijk voor Windows-compatibiliteit
artikelen =bereik(10)
met multiprocessing.Pool(processes=multiprocessing.cpu_count()) als pool:
resultaten =pool.map(process_item, items)
afdrukken(resultaten)
```
* `multiprocessing.Pool` creëert een pool van werkprocessen.
* `pool.map` past gelijktijdig `process_item` toe op elk item in `items`. Het retourneert een lijst met resultaten in dezelfde volgorde als de invoer.
* `multiprocessing.cpu_count()` bepaalt het aantal CPU-kernen, waardoor optimaal parallellisme mogelijk is. Indien nodig kunt u een kleiner aantal processen opgeven.
2. `concurrent.futures`: Dit biedt een interface op een hoger niveau voor zowel threads als processen, wat meer flexibiliteit biedt. Voor CPU-gebonden taken zul je `ProcessPoolExecutor` willen gebruiken.
```python
importeer gelijktijdige.futures
def proces_item(item):
"""De functie die parallel moet worden uitgevoerd."""
# Hier vindt u uw code om één item te verwerken.
resultaat =item * 2 # Voorbeeld:verdubbel het item
retourneer item, resultaat #return zowel invoer als uitvoer om bij te houden
als __naam__ =='__hoofd__':
artikelen =bereik(10)
met concurrent.futures.ProcessPoolExecutor() als uitvoerder:
resultaten =uitvoerder.map(process_item, items) #order bewaard
voor item, resultaat in resultaten:
print(f"Invoer:{item}, uitvoer:{resultaat}")
```
`concurrent.futures` biedt meer controle, vooral met `executor.submit` voor individuele taken en het afhandelen van uitzonderingen.
3. `threading` (Over het algemeen niet aanbevolen voor CPU-gebonden taken): Threading is geschikt voor I/O-gebonden taken (taken die het grootste deel van hun tijd besteden aan het wachten op externe bronnen, zoals netwerkverzoeken of schijfbewerkingen). Vanwege de GIL bieden threads in CPython geen echt parallellisme voor CPU-gebonden taken.
```python
draadsnijden importeren
def proces_item(item, resultaten):
#Uw code om één item te verwerken vindt u hier.
resultaat =item * 2 #Voorbeeld:verdubbel het item
resultaten.append(resultaat)
als __naam__ =='__hoofd__':
artikelen =bereik(10)
resultaten =[]
draden =[]
voor artikel in artikelen:
thread =threading.Thread(target=process_item, args=(item, resultaten))
threads.append(thread)
draad.start()
voor draad in draad:
draad.join()
afdrukken(resultaten)
```
Dit voorbeeld maakt gebruik van een gedeelde lijst ("resultaten") die zorgvuldig moet worden overwogen voor de veiligheid van threads (waar nodig met behulp van vergrendelingen). Het is complexer dan 'multiprocessing' of 'concurrent.futures' voor CPU-gebonden workloads en zal daar waarschijnlijk geen prestatieverbetering voor opleveren.
De juiste methode kiezen:
* CPU-gebonden: Gebruik `multiprocessing` of `concurrent.futures` met `ProcessPoolExecutor`. 'multiprocessing' is over het algemeen eenvoudiger voor eenvoudige bewerkingen in kaartverkleining.
* I/O-gebonden: Gebruik `threading` of `concurrent.futures` met `ThreadPoolExecutor`. `concurrent.futures` biedt betere afhandeling en controle van uitzonderingen.
* Gemengd: Mogelijk is een hybride aanpak nodig, waarbij processen voor CPU-intensieve onderdelen en threads voor I/O-gebonden onderdelen worden gecombineerd.
Vergeet niet om potentiële uitzonderingen binnen uw werkfuncties af te handelen en rekening te houden met de overhead van het maken en beheren van processen of threads. Voor zeer kleine taken kan de overhead groter zijn dan de voordelen van parallellisatie. Profileer uw code om te bepalen of parallellisatie daadwerkelijk een prestatieverbetering oplevert. |