Modulen `concurrent` i Python

Modulen `concurrent` i Python

I denna artikel kommer vi att förklara modulen concurrent i Python.

Samtidigt som vi klargör begreppen samtidighet och parallellism, kommer vi att förklara hur man implementerar asynkron bearbetning med hjälp av modulen concurrent och praktiska exempel.

YouTube Video

Modulen concurrent i Python

När man vill snabba upp bearbetningen i Python är det viktigt att vara medveten om skillnaden mellan samtidighet och parallellism. Modulen concurrent är ett viktigt sätt att hantera asynkron bearbetning på ett säkert och enkelt sätt med dessa skillnader i åtanke.

Skillnaden mellan samtidighet och parallellism

  • Samtidighet innebär att utforma en process så att flera uppgifter fortskrider genom att växla mellan dem i små arbetsenheter. Även om uppgifter inte körs faktiskt samtidigt, kan man genom att utnyttja "väntetid" göra hela processen mer effektiv.

  • Parallellism är en mekanism som fysiskt utför flera uppgifter samtidigt. Genom att använda flera CPU-kärnor utförs bearbetning samtidigt.

Båda är tekniker för att snabba upp bearbetning, men samtidighet är en designfråga om 'hur det ska fortskrida', medan parallellism är en genomförandefråga om 'hur det körs', vilket gör dem grundläggande olika.

Vad är modulen concurrent?

concurrent är ett standardbibliotek i Python som erbjuder ett högnivå-API för att hantera samtidighet och parallellism på ett säkert och enkelt sätt. Den är utformad så att du kan fokusera på att 'köra uppgifter' utan att behöva bekymra dig om lågnivåoperationer som att skapa och hantera trådar eller processer.

Roller för ThreadPoolExecutor och ProcessPoolExecutor

Modulen concurrent erbjuder två huvudsakliga alternativ beroende på uppgiftens natur.

  • ThreadPoolExecutor Detta passar för samtidiga implementationer, särskilt uppgifter med mycket I/O-väntan, som nätverks- eller filoperationer. Genom att växla mellan uppgifter utnyttjar man väntetid effektivt.

  • ProcessPoolExecutor Denna implementation är inriktad på parallellbearbetning och passar för CPU-intensiva uppgifter. Den använder flera processer för att fullt utnyttja tillgängliga CPU-kärnor parallellt.

En huvudfunktion i modulen concurrent är alltså att den erbjuder en struktur som låter dig välja mellan samtidighet och parallellism på rätt sätt efter behov.

Grundläggande om ThreadPoolExecutor (för I/O-uppgifter)

ThreadPoolExecutor passar för I/O-baserade uppgifter, som nätverkskommunikation och filoperationer. Den fördelar uppgifter mellan flera trådar och utnyttjar väntetid effektivt.

 1from concurrent.futures import ThreadPoolExecutor
 2import time
 3
 4def fetch_data(n):
 5    # Simulate an I/O-bound task
 6    time.sleep(1)
 7    return f"data-{n}"
 8
 9with ThreadPoolExecutor(max_workers=3) as executor:
10    futures = [executor.submit(fetch_data, i) for i in range(5)]
11
12    for future in futures:
13        print(future.result())
  • I detta exempel körs flera I/O-uppgifter som väntar en sekund samtidigt. Genom att använda submit registreras funktionsanrop som asynkrona uppgifter, och genom att anropa result() kan du vänta på slutförande och få resultat – detta gör det möjligt att på ett koncist sätt implementera samtidiga processer som effektivt utnyttjar väntetid.

Enkel samtidighet med map

Om avancerad kontroll inte behövs kan användandet av map göra din kod mer koncis.

 1from concurrent.futures import ThreadPoolExecutor
 2import time
 3
 4def fetch_data(n):
 5    # Simulate an I/O-bound task
 6    time.sleep(1)
 7    return f"data-{n}"
 8
 9with ThreadPoolExecutor(max_workers=3) as executor:
10    results = executor.map(fetch_data, range(5))
11
12    for result in results:
13        print(result)
  • I detta exempel körs flera I/O-uppgifter samtidigt med ThreadPoolExecutor.map. Eftersom map returnerar resultat i samma ordning som indata kan du skriva kod nära sekventiell bearbetning, och samtidig körning är möjlig utan att behöva tänka på asynkron bearbetning—det är en stor fördel.

Grundläggande om ProcessPoolExecutor (för CPU-bundna uppgifter)

För tunga beräkningar som utnyttjar CPU:n till fullo bör du använda processer istället för trådar. Detta gör det möjligt att undvika begränsningen Global Interpreter Lock (GIL).

 1from concurrent.futures import ProcessPoolExecutor
 2
 3def heavy_calculation(n):
 4    # Simulate a CPU-bound task
 5    total = 0
 6    for i in range(10_000_000):
 7        total += i * n
 8    return total
 9
10if __name__ == "__main__":
11    with ProcessPoolExecutor(max_workers=4) as executor:
12        results = executor.map(heavy_calculation, range(4))
13
14        for result in results:
15            print(result)

I detta exempel körs CPU-intensiva beräkningar parallellt med hjälp av ProcessPoolExecutor. Eftersom processer skapas behövs en __main__-vakt, vilket möjliggör säker parallell bearbetning med flera CPU-kärnor.

Bearbetning efter slutförande med as_completed

as_completed är användbar när du vill hantera resultat i den ordning de slutförs.

 1from concurrent.futures import ThreadPoolExecutor, as_completed
 2import time
 3
 4def fetch_data(n):
 5    # Simulate an I/O-bound task
 6    time.sleep(1)
 7    return f"data-{n}"
 8
 9with ThreadPoolExecutor(max_workers=3) as executor:
10    futures = [executor.submit(fetch_data, i) for i in range(5)]
11
12    for future in as_completed(futures):
13        print(future.result())
  • I detta exempel körs flera asynkrona uppgifter samtidigt och resultaten hämtas i den ordning de blir klara. Genom att använda as_completed kan du hantera resultat snabbt oavsett uppgifternas ordning, vilket gör det lämpligt för visning av förlopp eller vid behov av sekventiell hantering.

Hantering av undantag

I concurrent kastas undantag när du anropar result().

 1from concurrent.futures import ThreadPoolExecutor
 2
 3def risky_task(n):
 4    # Simulate a task that may fail for a specific input
 5    if n == 3:
 6        raise ValueError("Something went wrong")
 7    return n * 2
 8
 9with ThreadPoolExecutor() as executor:
10    futures = [executor.submit(risky_task, i) for i in range(5)]
11
12    for future in futures:
13        try:
14            print(future.result())
15        except Exception as e:
16            print("Error:", e)
  • Detta exempel visar att även om vissa uppgifter ger undantag så fortsätter övriga att köras och du kan hantera undantag individuellt när du hämtar resultaten. Genom att använda Futures i concurrent är det viktigt att både lyckade och misslyckade asynkrona körningar kan hanteras säkert.

Riktlinjer för att välja mellan trådar och processer

För att använda samtidighet och parallellism effektivt är det viktigt att välja rätt metod beroende på uppgiftens karaktär.

I praktiken kan följande kriterier hjälpa dig att välja.

  • För processer med mycket I/O-väntan, till exempel kommunikation eller filoperationer, använd ThreadPoolExecutor.
  • För CPU-bundna, tunga beräkningsuppgifter, använd ProcessPoolExecutor.
  • Om det finns många enkla uppgifter låter användandet av map dig skriva mer koncis kod.
  • Om exakt kontroll av körordningen eller undantagshantering är viktigt, kombinera submit med as_completed.

Fördelar med att använda concurrent

Genom att använda modulen concurrent kan du hantera asynkron bearbetning säkert och intuitivt.

De viktigaste fördelarna är:.

  • Du behöver inte bry dig om lågnivåhantering av trådar eller processer.
  • Det ingår i Pythons standardbibliotek, så du kan använda det med trygghet.
  • Koden blir mer läsbar och lättskött.
  • Det är idealiskt som ett första steg för att lära sig om samtidighet och parallellism.

Att bara ha dessa riktlinjer i åtanke kan kraftigt minska risken för fel vid användning av concurrent.

Sammanfattning

Modulen concurrent är standardalternativet för praktisk samtidighet och parallellism i Python. Det låter dig öka prestandan utan att behöva ändra innehållet i din bearbetning, vilket är en stor fördel i praktiken. Genom att använda concurrent kan du koncist implementera asynkron bearbetning samtidigt som du hanterar undantag och exekveringskontroll på ett säkert sätt.

Du kan följa med i artikeln ovan med hjälp av Visual Studio Code på vår YouTube-kanal. Vänligen kolla även in YouTube-kanalen.

YouTube Video