Python Threading: An Introduction – adminvista.com

I den här handledningen kommer du att lära dig hur du använder Pythons inbyggda trådningsmodul för att utforska flertrådsfunktioner i Python.

Från och med grunderna för processer och trådar kommer du att lära dig hur multithreading fungerar i Python – samtidigt som du förstår begreppen samtidighet och parallellism. Du kommer sedan att lära dig hur du startar och kör en eller flera trådar i Python med hjälp av den inbyggda trådningsmodulen.

Låt oss börja.

Processer kontra trådar: Vad är skillnaderna?

Vad är en process?

En process är varje instans av ett program som behöver köras.

Det kan vara vad som helst – ett Python-skript eller en webbläsare som Chrome till en videokonferensapplikation. Om du startar Aktivitetshanteraren på din maskin och navigerar till Prestanda –> CPU, kommer du att kunna se processerna och trådarna som för närvarande körs på dina CPU-kärnor.

Förstå processer och trådar

Internt har en process ett dedikerat minne som lagrar koden och data som motsvarar processen.

En process består av en eller flera trådar. En tråd är den minsta sekvens av instruktioner som operativsystemet kan exekvera, och den representerar flödet av exekvering.

Varje tråd har sin egen stack och register men inte ett dedikerat minne. Alla trådar som är associerade med en process kan komma åt data. Därför delas data och minne av alla trådar i en process.

I en CPU med N kärnor kan N processer köras parallellt vid samma tidpunkt. Två trådar av samma process kan dock aldrig köras parallellt – utan kan köras samtidigt. Vi kommer att ta upp begreppet samtidighet vs parallellism i nästa avsnitt.

Baserat på vad vi har lärt oss hittills, låt oss sammanfatta skillnaderna mellan en process och en tråd.

FeatureProcessThreadMemoryDedikerat minneDelat minne UtförandelägeParallell, samtidigKonkurrent; men inte parallellexekvering som hanteras av Operating SystemCPython Interpreter

Multithreading i Python

I Python säkerställer Global Interpreter Lock (GIL) att endast en tråd kan förvärva låset och köra när som helst. Alla trådar bör få detta lås för att köras. Detta säkerställer att endast en enda tråd kan köras – vid en given tidpunkt – och undviker samtidig flertrådning.

Tänk till exempel två trådar, t1 och t2, i samma process. Eftersom trådar delar samma data när t1 läser ett visst värde k, kan t2 ändra samma värde k. Detta kan leda till låsningar och oönskade resultat. Men bara en av trådarna kan skaffa låset och köra i vilket fall som helst. Därför säkerställer GIL även gängsäkerhet.

Så hur uppnår vi flertrådsfunktioner i Python? För att förstå detta, låt oss diskutera begreppen samtidighet och parallellism.

Samtidighet vs. parallellism: en översikt

Tänk på en CPU med mer än en kärna. I illustrationen nedan har CPU:n fyra kärnor. Det betyder att vi kan ha fyra olika operationer igång parallellt vid varje givet ögonblick.

Om det finns fyra processer kan var och en av processerna köras oberoende och samtidigt på var och en av de fyra kärnorna. Låt oss anta att varje process har två trådar.

För att förstå hur trådning fungerar, låt oss byta från flerkärnig till enkärnig processorarkitektur. Som nämnts kan endast en enda tråd vara aktiv vid en viss exekveringsinstans; men processorkärnan kan växla mellan trådarna.

Till exempel väntar ofta I/O-bundna trådar på I/O-operationer: läsning av användarinmatning, databasläsning och filoperationer. Under denna väntetid kan den släppa låset så att den andra tråden kan löpa. Väntetiden kan också vara en enkel operation som att sova i n sekunder.

Sammanfattningsvis: Under vänteoperationer släpper tråden låset, vilket gör att processorkärnan kan byta till en annan tråd. Den tidigare tråden återupptas körningen efter att vänteperioden är klar. Denna process, där processorkärnan växlar mellan trådarna samtidigt, underlättar multithreading. ✅

Om du vill implementera parallellitet på processnivå i din applikation, överväg att använda multiprocessing istället.

Python Threading Module: Första stegen

Python levereras med en trådningsmodul som du kan importera till Python-skriptet.

import threading

För att skapa ett trådobjekt i Python kan du använda trådkonstruktorn: threading.Thread(…). Detta är den generiska syntaxen som räcker för de flesta trådningsimplementeringar:

threading.Thread(target=...,args=...)

Här,

  • target är nyckelordsargumentet som anger en Python-anropbar
  • args är den tuppel av argument som målet tar in.

Du behöver Python 3.x för att köra kodexemplen i denna handledning. Ladda ner koden och följ med.

Hur man definierar och kör trådar i Python

Låt oss definiera en tråd som kör en målfunktion.

Målfunktionen är some_func.

import threading
import time

def some_func():
    print("Running some_func...")
    time.sleep(2)
    print("Finished running some_func.")

thread1 = threading.Thread(target=some_func)
thread1.start()
print(threading.active_count())

Låt oss analysera vad kodavsnittet ovan gör:

  • Den importerar gängnings- och tidsmodulerna.
  • Funktionen some_func har beskrivande print()-satser och inkluderar en vilooperation i två sekunder: time.sleep(n) gör att funktionen vilar i n sekunder.
  • Därefter definierar vi en tråd thread_1 med målet som some_func. threading.Thread(target=…) skapar ett trådobjekt.
  • Obs: Ange namnet på funktionen och inte ett funktionsanrop; använd some_func och inte some_func().
  • Att skapa ett trådobjekt startar inte en tråd. anropar start()-metoden på trådobjektet gör det.
  • För att få antalet aktiva trådar använder vi funktionen active_count() .

Python-skriptet körs på huvudtråden, och vi skapar en annan tråd (tråd1) för att köra funktionen some_func så att antalet aktiva trådar är två, som framgår av utgången:

# Output
Running some_func...
2
Finished running some_func.

Om vi ​​tittar närmare på utgången ser vi att när tråd1 startas körs den första utskriftssatsen. Men under viloläget växlar processorn till huvudtråden och skriver ut antalet aktiva trådar – utan att vänta på att tråd1 ska slutföras.

Väntar på att trådarna ska slutföras

Om du vill att tråd1 ska avsluta exekveringen kan du anropa metoden join() på den efter att tråden har startat. Om du gör det väntar du på att tråd1 ska slutföras utan att byta till huvudtråden.

import threading
import time

def some_func():
    print("Running some_func...")
    time.sleep(2)
    print("Finished running some_func.")

thread1 = threading.Thread(target=some_func)
thread1.start()
thread1.join()
print(threading.active_count())

Nu har tråd1 körts klart innan vi skriver ut antalet aktiva trådar. Så bara huvudtråden körs, vilket betyder att antalet aktiva trådar är en. ✅

# Output
Running some_func...
Finished running some_func.
1

Hur man kör flera trådar i Python

Låt oss sedan skapa två trådar för att köra två olika funktioner.

Här är count_down en funktion som tar in ett tal som argument och räknar ner från det numret till noll.

def count_down(n):
    for i in range(n,-1,-1):
        print(i)

Vi definierar count_up, en annan Python-funktion som räknar från noll upp till ett givet tal.

def count_up(n):
    for i in range(n+1):
        print(i)

📑 När du använder funktionen range() med syntaxområdet (start, stopp, steg), exkluderas slutpunktstoppet som standard.

– För att räkna ner från ett specifikt tal till noll kan du använda ett negativt stegvärde på -1 och sätta stoppvärdet till -1 så att noll ingår.

– På samma sätt, för att räkna upp till n, måste du ställa in stoppvärdet till n + 1. Eftersom standardvärdena för start och steg är 0 respektive 1, kan du använda range(n + 1) för att få sekvensen 0 genom n.

Därefter definierar vi två trådar, tråd1 och tråd2 för att köra funktionerna count_down respektive count_up. Vi lägger till utskrifter och vilolägen för båda funktionerna.

När du skapar trådobjekten, lägg märke till att argumenten till målfunktionen ska anges som en tuppel—till parametern args. Eftersom båda funktionerna (count_down och count_up) tar in ett argument. Du måste infoga ett kommatecken uttryckligen efter värdet. Detta säkerställer att argumentet fortfarande skickas in som en tupel, eftersom de efterföljande elementen antas vara Inga.

import threading
import time

def count_down(n):
    for i in range(n,-1,-1):
        print("Running thread1....")
        print(i)
        time.sleep(1)


def count_up(n):
    for i in range(n+1):
        print("Running thread2...")
        print(i)
        time.sleep(1)

thread1 = threading.Thread(target=count_down,args=(10,))
thread2 = threading.Thread(target=count_up,args=(5,))
thread1.start()
thread2.start()

I utgången:

  • Funktionen count_up körs på tråd2 och räknar upp till 5 från 0.
  • Nedräkningsfunktionen körs på tråd1 räknar ner från 10 till 0.
# Output
Running thread1....
10
Running thread2...
0
Running thread1....
9
Running thread2...
1
Running thread1....
8
Running thread2...
2
Running thread1....
7
Running thread2...
3
Running thread1....
6
Running thread2...
4
Running thread1....
5
Running thread2...
5
Running thread1....
4
Running thread1....
3
Running thread1....
2
Running thread1....
1
Running thread1....
0

Du kan se att tråd1 och tråd2 körs omväxlande, eftersom båda involverar en väntaoperation (sömn). När count_up-funktionen har slutat räkna upp till 5 är tråd2 inte längre aktiv. Så vi får utdata som motsvarar endast tråd1.

Summering

I den här handledningen har du lärt dig hur du använder Pythons inbyggda trådningsmodul för att implementera multithreading. Här är en sammanfattning av de viktigaste takeaways:

  • Trådkonstruktorn kan användas för att skapa ett trådobjekt. Genom att använda threading.Thread(target=,args=()) skapas en tråd som kör målet callable med argument specificerade i args.
  • Python-programmet körs på en huvudtråd, så trådobjekten du skapar är ytterligare trådar. Du kan anropa active_count()-funktionen returnerar antalet aktiva trådar vid vilken instans som helst.
  • Du kan starta en tråd med metoden start() på trådobjektet och vänta tills den är klar med exekveringen med metoden join().

Du kan koda ytterligare exempel genom att justera väntetiderna, försöka med en annan I/O-operation och mer. Se till att implementera multithreading i dina kommande Python-projekt. Lycka till med kodningen!🎉