threading — Trådbaserad parallellism

Källkod: Lib/threading.py


Denna modul konstruerar trådningsgränssnitt på högre nivå ovanpå modulen _thread på lägre nivå.

Tillgänglighet: not WASI.

Den här modulen fungerar inte eller är inte tillgänglig på WebAssembly. Se WebAssembly-plattformar för mer information.

Introduktion

Modulen threading ger möjlighet att köra flera threads (mindre enheter av en process) samtidigt inom en och samma process. Den gör det möjligt att skapa och hantera trådar, vilket gör det möjligt att utföra uppgifter parallellt och dela minnesutrymme. Trådar är särskilt användbara när uppgifter är I/O-bundna, t.ex. filoperationer eller nätverksförfrågningar, där en stor del av tiden går åt till att vänta på externa resurser.

Ett typiskt användningsområde för threading är att hantera en pool av arbetstrådar som kan bearbeta flera uppgifter samtidigt. Här är ett grundläggande exempel på att skapa och starta trådar med Thread:

import threading
import time

def crawl(link, delay=3):
    print(f"crawl started for {link}")
    time.sleep(delay)  # Blocking I/O (simulating a network request)
    print(f"crawl ended for {link}")

links = [
    "https://python.org",
    "https://docs.python.org",
    "https://peps.python.org",
]

# Start threads for each link
threads = []
for link in links:
    # Using `args` to pass positional arguments and `kwargs` for keyword arguments
    t = threading.Thread(target=crawl, args=(link,), kwargs={"delay": 2})
    threads.append(t)

# Start each thread
for t in threads:
    t.start()

# Wait for all threads to finish
for t in threads:
    t.join()

Ändrad i version 3.7: Denna modul var tidigare valfri, men är nu alltid tillgänglig.

Se även

concurrent.futures.ThreadPoolExecutor erbjuder ett gränssnitt på högre nivå för att flytta uppgifter till en bakgrundstråd utan att blockera exekveringen av den anropande tråden, samtidigt som man kan hämta resultaten när det behövs.

queue tillhandahåller ett trådsäkert gränssnitt för utbyte av data mellan pågående trådar.

asyncio erbjuder en alternativ metod för att uppnå samtidighet på uppgiftsnivå utan att behöva använda flera operativsystemtrådar.

Anteckning

I Python 2.x-serien innehöll denna modul camelCase-namn för vissa metoder och funktioner. Dessa är föråldrade från och med Python 3.10, men de stöds fortfarande för kompatibilitet med Python 2.5 och lägre.

I CPython, på grund av Global Interpreter Lock, kan endast en tråd exekvera Python-kod samtidigt (även om vissa prestandaorienterade bibliotek kan övervinna denna begränsning). Om du vill att din applikation ska utnyttja beräkningsresurserna i flerkärniga maskiner bättre rekommenderas du att använda multiprocessing eller concurrent.futures.ProcessPoolExecutor. Trådning är dock fortfarande en lämplig modell om du vill köra flera I/O-bundna uppgifter samtidigt.

GIL och prestandaöverväganden

Till skillnad från multiprocessing-modulen, som använder separata processer för att kringgå global interpreter lock (GIL), arbetar threading-modulen inom en enda process, vilket innebär att alla trådar delar samma minnesutrymme. GIL begränsar dock prestandavinsterna med trådning när det gäller CPU-bundna uppgifter, eftersom endast en tråd kan exekvera Python-bytekod åt gången. Trots detta är trådar fortfarande ett användbart verktyg för att uppnå samtidighet i många scenarier.

Från och med Python 3.13 kan free-threaded-byggnationer inaktivera GIL, vilket möjliggör äkta parallellkörning av trådar, men den här funktionen är inte tillgänglig som standard (se PEP 703).

Referens

Denna modul definierar följande funktioner:

threading.active_count()

Returnerar antalet Thread-objekt som för närvarande lever. Antalet som returneras är lika med längden på listan som returneras av enumerate().

Funktionen activeCount är ett föråldrat alias för denna funktion.

threading.current_thread()

Returnerar det aktuella Thread-objektet, motsvarande den anropande enhetens kontrolltråd. Om anroparens kontrolltråd inte skapades genom modulen threading, returneras ett dummy-trådobjekt med begränsad funktionalitet.

Funktionen currentThread är ett föråldrat alias för denna funktion.

threading.excepthook(args, /)

Hantera undantag som uppkommit genom Thread.run().

Argumentet args har följande attribut:

  • exc_type: Typ av undantag.

  • exc_värde: Undantagsvärde, kan vara None.

  • exc_traceback: Exception traceback, kan vara None.

  • tråd: Tråd som orsakade undantaget, kan vara None.

Om exc_type är SystemExit, ignoreras undantaget i tysthet. Annars skrivs undantaget ut på sys.stderr.

Om denna funktion ger upphov till ett undantag anropas sys.excepthook() för att hantera det.

threading.excepthook() kan åsidosättas för att styra hur obehandlade undantag som tas upp av Thread.run() hanteras.

Att lagra exc_value med en anpassad hook kan skapa en referenscykel. Den bör rensas explicit för att bryta referenscykeln när undantaget inte längre behövs.

Om du lagrar thread med en anpassad hook kan den återuppstå om den är inställd på ett objekt som håller på att slutföras. Undvik att lagra thread efter att den anpassade hooken har slutförts för att undvika att objekt återuppstår.

Se även

sys.excepthook() hanterar undantag som inte fångats upp.

Tillagd i version 3.8.

threading.__excepthook__

Innehåller det ursprungliga värdet av threading.excepthook(). Det sparas så att det ursprungliga värdet kan återställas om de skulle råka ersättas med trasiga eller alternativa objekt.

Tillagd i version 3.10.

threading.get_ident()

Returnerar ”trådidentifieraren” för den aktuella tråden. Detta är ett heltal som inte är noll. Dess värde har ingen direkt betydelse; det är avsett som en magisk cookie som kan användas t.ex. för att indexera en ordbok med trådspecifika data. Trådidentifierare kan återanvändas när en tråd avslutas och en ny tråd skapas.

Tillagd i version 3.3.

threading.get_native_id()

Returnerar det inbyggda integrerade tråd-ID:t för den aktuella tråden som tilldelats av kärnan. Detta är ett icke-negativt heltal. Dess värde kan användas för att unikt identifiera just denna tråd i hela systemet (tills tråden avslutas, varefter värdet kan återanvändas av operativsystemet).

Tillgänglighet: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX, DragonFlyBSD, GNU/kFreeBSD.

Tillagd i version 3.8.

Ändrad i version 3.13: Lagt till stöd för GNU/kFreeBSD.

threading.enumerate()

Returnerar en lista över alla Thread-objekt som för närvarande är aktiva. Listan inkluderar daemoniska trådar och dummy-trådobjekt som skapats av current_thread(). Den utesluter avslutade trådar och trådar som ännu inte har startats. Huvudtråden är dock alltid en del av resultatet, även när den har avslutats.

threading.main_thread()

Returnerar huvudobjektet Thread. Under normala förhållanden är huvudtråden den tråd från vilken Python-tolken startades.

Tillagd i version 3.4.

threading.settrace(func)

Ställ in en spårningsfunktion för alla trådar som startas från modulen threading. func kommer att skickas till sys.settrace() för varje tråd, innan dess run() metod anropas.

threading.settrace_all_threads(func)

Ställ in en spårningsfunktion för alla trådar som startas från modulen threading och alla Python-trådar som körs för närvarande.

func kommer att skickas till sys.settrace() för varje tråd, innan dess run()-metod anropas.

Tillagd i version 3.12.

threading.gettrace()

Hämta spårningsfunktionen som den ställts in av settrace().

Tillagd i version 3.10.

threading.setprofile(func)

Ställ in en profilfunktion för alla trådar som startas från modulen threading. func kommer att skickas till sys.setprofile() för varje tråd, innan dess run()-metod anropas.

threading.setprofile_all_threads(func)

Ange en profilfunktion för alla trådar som startas från modulen threading och alla Python-trådar som körs för närvarande.

func kommer att skickas till sys.setprofile() för varje tråd, innan dess run()-metod anropas.

Tillagd i version 3.12.

threading.getprofile()

Hämta den profileringsfunktion som ställts in av setprofile().

Tillagd i version 3.10.

threading.stack_size([size])

Returnerar den trådstackstorlek som används när nya trådar skapas. Det valfria argumentet size anger den stackstorlek som ska användas för senare skapade trådar och måste vara 0 (använd plattformens eller konfigurerade standard) eller ett positivt heltalsvärde på minst 32 768 (32 KiB). Om size inte anges används 0. Om ändring av trådstackens storlek inte stöds, uppstår ett RuntimeError. Om den angivna stackstorleken är ogiltig, uppstår ett ValueError och stackstorleken ändras inte. 32 KiB är för närvarande det minsta stödda stackstorleksvärdet för att garantera tillräckligt med stackutrymme för själva tolken. Observera att vissa plattformar kan ha särskilda restriktioner för värden på stackstorleken, t.ex. att den minsta stackstorleken måste vara > 32 KiB eller att allokering måste ske i multiplar av sidstorleken i systemminnet - plattformsdokumentationen bör läsas för mer information (4 KiB-sidor är vanliga; att använda multiplar av 4096 för stackstorleken är det föreslagna tillvägagångssättet i avsaknad av mer specifik information).

Tillgänglighet: Windows, pthreads.

Unix-plattformar med stöd för POSIX-trådar.

Denna modul definierar också följande konstant:

threading.TIMEOUT_MAX

Det högsta tillåtna värdet för parametern timeout i blockeringsfunktioner (Lock.acquire(), RLock.acquire(), Condition.wait(), etc.). Om du anger en timeout som är större än detta värde kommer ett OverflowError att uppstå.

Tillagd i version 3.2.

Denna modul definierar ett antal klasser som beskrivs närmare i avsnitten nedan.

Utformningen av denna modul är löst baserad på Javas trådningsmodell. Men där Java gör lås och villkorliga variabler till grundläggande beteende för varje objekt, är de separata objekt i Python. Pythons Thread-klass stöder en delmängd av beteendet hos Javas Thread-klass; för närvarande finns det inga prioriteringar, inga trådgrupper och trådar kan inte förstöras, stoppas, avbrytas, återupptas eller avbrytas. De statiska metoderna i Javas Thread-klass mappas, när de implementeras, till funktioner på modulnivå.

Alla metoder som beskrivs nedan utförs atomiskt.

Trådlokala data

Trådlokala data är data vars värden är trådspecifika. Om du har data som du vill ska vara lokala för en tråd skapar du ett local-objekt och använder dess attribut:

>>> mydata = local()
>>> mydata.number = 42
>>> mydata.number
42

Du kan också komma åt local-objektets ordbok:

>>> mydata.__dict__
{'number': 42}
>>> mydata.__dict__.setdefault('widgets', [])
[]
>>> mydata.widgets
[]

Om vi kommer åt data i en annan tråd:

>>> log = []
>>> def f():
...     items = sorted(mydata.__dict__.items())
...     log.append(items)
...     mydata.number = 11
...     log.append(mydata.number)

>>> import threading
>>> thread = threading.Thread(target=f)
>>> thread.start()
>>> thread.join()
>>> log
[[], 11]

får vi olika data. Dessutom påverkar ändringar som gjorts i den andra tråden inte data som ses i den här tråden:

>>> mydata.number
42

Naturligtvis gäller värden som du får från ett local-objekt, inklusive deras __dict__-attribut, för den tråd som var aktuell när attributet lästes. Av den anledningen vill du i allmänhet inte spara dessa värden i olika trådar, eftersom de endast gäller för den tråd de kom från.

Du kan skapa egna local-objekt genom att underklassa local-klassen:

>>> class MyLocal(local):
...     number = 2
...     def __init__(self, /, **kw):
...         self.__dict__.update(kw)
...     def squared(self):
...         return self.number ** 2

Detta kan vara användbart för att stödja standardvärden, metoder och initialisering. Observera att om du definierar en __init__()-metod kommer den att anropas varje gång local-objektet används i en separat tråd. Detta är nödvändigt för att initiera varje tråds dictionary.

Om vi nu skapar ett local-objekt:

>>> mydata = MyLocal(color='red')

vi har ett standardnummer:

>>> mydata.number
2

en initial färg:

>>> mydata.color
'red'
>>> del mydata.color

Och en metod som fungerar på data:

>>> mydata.squared()
4

Precis som tidigare kan vi komma åt data i en separat tråd:

>>> log = []
>>> thread = threading.Thread(target=f)
>>> thread.start()
>>> thread.join()
>>> log
[[('color', 'red')], 11]

utan att påverka den här trådens data:

>>> mydata.number
2
>>> mydata.color
Traceback (most recent call last):
...
AttributeError: 'MyLocal' object has no attribute 'color'

Observera att underklasser kan definiera __slots__, men de är inte trådlokala. De delas mellan olika trådar:

>>> class MyLocal(local):
...     __slots__ = 'number'

>>> mydata = MyLocal()
>>> mydata.number = 42
>>> mydata.color = 'red'

Så, den separata tråden:

>>> thread = threading.Thread(target=f)
>>> thread.start()
>>> thread.join()

påverkar vad vi ser:

>>> mydata.number
11
class threading.local

En klass som representerar trådlokala data.

Trådobjekt

Klassen Thread representerar en aktivitet som körs i en separat kontrolltråd. Det finns två sätt att specificera aktiviteten: genom att skicka ett anropsbart objekt till konstruktören eller genom att åsidosätta metoden run() i en subklass. Inga andra metoder (förutom konstruktören) bör åsidosättas i en subklass. Med andra ord, endast åsidosätt metoderna __init__() och run() i denna klass.

När ett trådobjekt har skapats måste dess aktivitet startas genom att anropa trådens metod start(). Detta anropar metoden run() i en separat kontrolltråd.

När trådens aktivitet har startat anses tråden vara ”levande”. Den slutar att vara levande när dess run()-metod avslutas – antingen normalt eller genom att ett ohanterat undantag uppstår. Metoden is_alive() testar om tråden är vid liv.

Andra trådar kan anropa en tråds join()-metod. Detta blockerar den anropande tråden tills den tråd vars join()-metod anropas har avslutats.

En tråd har ett namn. Namnet kan skickas till konstruktören och läsas eller ändras genom attributet name.

Om metoden run() ger upphov till ett undantag anropas threading.excepthook() för att hantera det. Som standard ignorerar threading.excepthook() tyst SystemExit.

En tråd kan flaggas som en ”daemon-tråd”. Betydelsen av denna flagga är att hela Python-programmet avslutas när det bara finns daemon-trådar kvar. Det initiala värdet ärvs från den skapande tråden. Flaggan kan sättas genom egenskapen daemon eller konstruktörsargumentet daemon.

Anteckning

Daemon-trådar stoppas plötsligt vid nedstängning. Deras resurser (t.ex. öppna filer, databastransaktioner etc.) kanske inte frigörs på rätt sätt. Om du vill att dina trådar ska sluta på ett elegant sätt, gör dem inte till daemoner och använd en lämplig signalmekanism, t.ex. en Event.

Det finns ett ”main thread”-objekt; detta motsvarar den första kontrolltråden i Python-programmet. Det är inte en daemon-tråd.

Det finns en möjlighet att ”dummy thread objects” skapas. Detta är trådobjekt som motsvarar ”främmande trådar”, dvs. kontrolltrådar som startas utanför trådningsmodulen, t.ex. direkt från C-kod. Dummy thread-objekt har begränsad funktionalitet; de betraktas alltid som levande och daemoniska, och kan inte joined. De raderas aldrig, eftersom det är omöjligt att upptäcka att främmande trådar har avslutats.

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None, context=None)

Denna konstruktor ska alltid anropas med nyckelordsargument. Argumenten är:

group bör vara None; reserverad för framtida tillägg när en ThreadGroup-klass implementeras.

target är det anropsbara objekt som ska anropas av metoden run(). Standardvärdet är None, vilket innebär att ingenting anropas.

name är trådens namn. Som standard konstrueras ett unikt namn av formen ”Thread-N” där N är ett litet decimaltal, eller ”Thread-N (target)” där ”target” är target.__name__ om argumentet target anges.

args är en lista eller tupel av argument för målanropet. Standardvärdet är ().

kwargs är en ordbok med nyckelordsargument för målanropet. Standardvärdet är {}.

Om inte None, anger daemon explicit om tråden är daemonisk. Om None (standard) ärvs daemonic-egenskapen från den aktuella tråden.

context är Context-värdet som ska användas när tråden startas. Standardvärdet är None vilket indikerar att sys.flags.thread_inherit_context-flaggan styr beteendet. Om flaggan är true kommer trådar att starta med en kopia av kontexten för den som anropar start(). Om den är false startar de med en tom kontext. För att uttryckligen starta med en tom kontext, skicka en ny instans av Context(). För att uttryckligen starta med en kopia av den aktuella kontexten, skicka värdet från copy_context(). Flaggan är som standard true på free-threaded builds och false annars.

Om subklassen åsidosätter konstruktorn måste den se till att anropa basklassens konstruktor (Thread.__init__()) innan den gör något annat med tråden.

Ändrad i version 3.3: Parametern daemon har lagts till.

Ändrad i version 3.10: Använd target-namnet om name-argumentet utelämnas.

Ändrad i version 3.14: Parametern context har lagts till.

start()

Starta trådens aktivitet.

Den får anropas högst en gång per trådobjekt. Den ordnar så att objektets run()-metod anropas i en separat kontrolltråd.

Denna metod kommer att ge upphov till ett RuntimeError om den anropas mer än en gång på samma trådobjekt.

Om det stöds, ange operativsystemets trådnamn till threading.Thread.name. Namnet kan avkortas beroende på operativsystemets begränsningar för trådnamn.

Ändrad i version 3.14: Ställ in operativsystemets trådnamn.

run()

Metod som representerar trådens aktivitet.

Du kan åsidosätta denna metod i en subklass. Standardmetoden run() anropar det anropsbara objekt som skickats till objektets konstruktör som target-argument, om något, med positions- och nyckelordsargument som hämtas från args- respektive kwargs-argumenten.

Om man använder list eller tuple som args-argument som skickas till Thread kan man uppnå samma effekt.

Exempel:

>>> from threading import Thread
>>> t = Thread(target=print, args=[1])
>>> t.run()
1
>>> t = Thread(target=print, args=(1,))
>>> t.run()
1
join(timeout=None)

Vänta tills tråden avslutas. Detta blockerar den anropande tråden tills den tråd vars join()-metod anropas avslutas – antingen normalt eller genom ett ohanterat undantag – eller tills den valfria timeouten inträffar.

När argumentet timeout finns med och inte None, ska det vara ett flyttal som anger en tidsgräns för operationen i sekunder (eller bråkdelar därav). Eftersom join() alltid returnerar None måste du anropa is_alive() efter join() för att avgöra om en timeout inträffat – om tråden fortfarande är vid liv har anropet av join() tidsavgränsats.

Om argumentet timeout inte finns med eller om det är None, blockeras åtgärden tills tråden avslutas.

En tråd kan anslutas många gånger.

join() ger upphov till ett RuntimeError om ett försök görs att ansluta till den aktuella tråden eftersom det skulle orsaka ett dödläge. Det är också ett fel att join() en tråd innan den har startats och försök att göra det ger upphov till samma undantag.

Om ett försök görs att ansluta till en pågående daemonisk tråd i ett sent skede av Python finalization ger join() upphov till ett PythonFinalizationError.

Ändrad i version 3.14: Kan ge upphov till PythonFinalizationError.

name

En sträng som endast används för identifieringsändamål. Den har ingen semantik. Flera trådar kan ges samma namn. Det initiala namnet sätts av konstruktören.

På vissa plattformar anges trådnamnet på operativsystemsnivå när tråden startar, så att det syns i aktivitetshanterare. Namnet kan trunkeras för att rymmas inom en systemspecifik gräns (t.ex. 15 byte på Linux eller 63 byte på macOS).

Ändringar av name återspeglas endast på OS-nivå när den tråd som körs för tillfället byter namn. (Att ställa in name-attributet för en annan tråd uppdaterar bara Python Thread-objektet)

getName()
setName()

Föråldrat getter/setter API för name; använd det direkt som en egenskap istället.

Föråldrad sedan version 3.10.

ident

Trådidentifieraren för denna tråd eller None om tråden inte har startats. Detta är ett heltal som inte är noll. Se funktionen get_ident(). Trådidentifierare kan återanvändas när en tråd avslutas och en ny tråd skapas. Identifieraren är tillgänglig även efter att tråden har avslutats.

native_id

Tråd-ID (TID) för denna tråd, som tilldelats av operativsystemet (kärnan). Detta är ett icke-negativt heltal, eller None om tråden inte har startats. Se funktionen get_native_id(). Detta värde kan användas för att unikt identifiera just denna tråd i hela systemet (tills tråden avslutas, varefter värdet kan återanvändas av operativsystemet).

Anteckning

I likhet med process-ID:n är tråd-ID:n endast giltiga (garanterat unika i hela systemet) från det att tråden skapas till dess att tråden har avslutats.

Tillgänglighet: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX, DragonFlyBSD.

Tillagd i version 3.8.

is_alive()

Returnerar om tråden är vid liv.

Denna metod returnerar True precis innan metoden run() startar till precis efter att metoden run() avslutas. Modulfunktionen enumerate() returnerar en lista över alla levande trådar.

daemon

Ett booleskt värde som anger om denna tråd är en daemon-tråd (True) eller inte (False). Detta måste anges innan start() anropas, annars kommer RuntimeError att aktiveras. Dess initiala värde ärvs från den tråd som skapar den; huvudtråden är inte en daemon-tråd och därför har alla trådar som skapas i huvudtråden som standard daemon = False.

Hela Python-programmet avslutas när inga levande icke-daemon-trådar finns kvar.

isDaemon()
setDaemon()

Föråldrad getter/setter API för daemon; använd den direkt som en egenskap istället.

Föråldrad sedan version 3.10.

Lås objekt

Ett primitivt lås är en synkroniseringsprimitiv som inte ägs av en viss tråd när den är låst. I Python är det för närvarande den lägsta tillgängliga synkroniseringsprimitiven, som implementeras direkt av tilläggsmodulen _thread.

Ett primitivt lås är i ett av två tillstånd, ”låst” eller ”olåst”. Det skapas i det olåsta tillståndet. Det har två grundläggande metoder, acquire() och release(). När tillståndet är upplåst ändrar acquire() tillståndet till locked och återgår omedelbart. När tillståndet är locked blockerar acquire() tills ett anrop till release() i en annan tråd ändrar det till unlocked, då återställer anropet till acquire() det till locked och returnerar. Metoden release() bör endast anropas i låst tillstånd; den ändrar tillståndet till olåst och returnerar omedelbart. Om ett försök görs att frigöra ett olåst lås, kommer ett RuntimeError att uppstå.

Lås stöder också context management protocol.

När mer än en tråd är blockerad i acquire() i väntan på att tillståndet ska övergå till olåst, fortsätter endast en tråd när ett anrop av release() återställer tillståndet till olåst; vilken av de väntande trådarna som fortsätter är inte definierat och kan variera mellan olika implementationer.

Alla metoder utförs atomiskt.

class threading.Lock

Klassen som implementerar primitiva låsobjekt. När en tråd har förvärvat ett lås blockeras efterföljande försök att förvärva det tills det släpps; vilken tråd som helst kan släppa det.

Ändrad i version 3.13: Lock är nu en klass. I tidigare Pythons var Lock en fabriksfunktion som returnerade en instans av den underliggande privata låstypen.

acquire(blocking=True, timeout=-1)

Förvärva ett lås, blockerande eller icke-blockerande.

När den anropas med argumentet blocking satt till True (standard), blockeras den tills låset låses upp, sedan sätts den till locked och returnerar True.

Blockera inte när anropet görs med argumentet blocking satt till False. Om ett anrop med blocking satt till True skulle blockera, returnera False omedelbart; i annat fall, sätt låset till locked och returnera True.

När timeout anropas med ett positivt värde för argumentet med flyttal, blockeras blockeringen i högst det antal sekunder som anges av timeout och så länge som låset inte kan förvärvas. Ett timeout-argument på -1 anger en obegränsad väntan. Det är förbjudet att ange en timeout när blocking är False.

Returvärdet är True om låset har förvärvats framgångsrikt, False om inte (t.ex. om timeout har löpt ut).

Ändrad i version 3.2: Parametern timeout är ny.

Ändrad i version 3.2: Låsinhämtning kan nu avbrytas av signaler på POSIX om den underliggande trådningsimplementationen stöder det.

Ändrad i version 3.14: Låsinhämtning kan nu avbrytas av signaler i Windows.

release()

Frigör ett lås. Detta kan anropas från vilken tråd som helst, inte bara från den tråd som har förvärvat låset.

När låset är låst återställer du det till olåst och återvänder. Om några andra trådar är blockerade i väntan på att låset ska låsas upp, tillåter du att exakt en av dem fortsätter.

När den anropas på ett olåst lås uppstår ett RuntimeError.

Det finns inget returvärde.

locked()

Returnerar True om låset är förvärvat.

RLock-objekt

Ett reentrant lås är en synkroniseringsprimitiv som kan förvärvas flera gånger av samma tråd. Internt använder det koncepten ”ägande tråd” och ”rekursionsnivå” utöver det låsta/olåsta tillstånd som används av primitiva lås. I låst tillstånd äger någon tråd låset; i olåst tillstånd äger ingen tråd det.

Trådar anropar ett lås acquire()-metod för att låsa det, och dess release()-metod för att låsa upp det.

Anteckning

Reentranta lås stöder context management protocol, så det rekommenderas att använda with istället för att manuellt anropa acquire() och release() för att hantera förvärv och frigörande av låset för ett kodblock.

RLocks anropspar acquire()/release() kan vara nästlade, till skillnad från Locks acquire()/release(). Endast det sista release() (det yttersta parets release()) återställer låset till ett olåst tillstånd och tillåter en annan tråd som blockerats i acquire() att fortsätta.

acquire()/release() måste användas i par: varje acquire måste ha en release i den tråd som har förvärvat låset. Om man inte anropar release lika många gånger som låset har förvärvats kan det leda till dödläge.

class threading.RLock

Denna klass implementerar objekt med återkommande lås. Ett reentrant lås måste släppas av den tråd som förvärvade det. När en tråd har förvärvat ett reentrant lås kan samma tråd förvärva det igen utan att blockera; tråden måste släppa det en gång för varje gång den har förvärvat det.

Observera att RLock faktiskt är en fabriksfunktion som returnerar en instans av den mest effektiva versionen av den konkreta RLock-klassen som stöds av plattformen.

acquire(blocking=True, timeout=-1)

Förvärva ett lås, blockerande eller icke-blockerande.

Se även

Användning av RLock som kontexthanterare

Rekommenderas framför manuella acquire()- och release()-anrop när det är praktiskt möjligt.

När den anropas med argumentet blocking inställt på True (standard):

  • Om ingen tråd äger låset, förvärvar du låset och återvänder omedelbart.

  • Om en annan tråd äger låset blockeras det tills vi kan förvärva låset eller timeout, om det är inställt på ett positivt floatvärde.

  • Om samma tråd äger låset, förvärvar du låset igen och återvänder omedelbart. Detta är skillnaden mellan Lock och RLock; Lock hanterar detta fall på samma sätt som det föregående och blockerar tills låset kan förvärvas.

När den anropas med argumentet blocking satt till False:

  • Om ingen tråd äger låset, förvärvar du låset och återvänder omedelbart.

  • Om en annan tråd äger låset, returnera omedelbart.

  • Om samma tråd äger låset, förvärvar du låset igen och återvänder omedelbart.

I samtliga fall, om tråden kunde förvärva låset, returneras True. Om tråden inte kunde förvärva låset (d.v.s. om den inte blockerade eller om timeouten uppnåddes) returneras False.

Om den anropas flera gånger kan det leda till dödläge om inte release() anropas lika många gånger. Överväg att använda RLock som en kontexthanterare istället för att anropa acquire/release direkt.

Ändrad i version 3.2: Parametern timeout är ny.

release()

Frigör ett lås och dekrementera rekursionsnivån. Om den efter dekrementeringen är noll, återställ låset till olåst (ägs inte av någon tråd), och om några andra trådar är blockerade i väntan på att låset ska bli olåst, låt exakt en av dem fortsätta. Om rekursionsnivån fortfarande inte är noll efter dekrementeringen förblir låset låst och ägs av den anropande tråden.

Anropa endast denna metod när den anropande tråden äger låset. Ett RuntimeError uppstår om denna metod anropas när låset inte är förvärvat.

Det finns inget returvärde.

locked()

Returnerar en boolean som anger om detta objekt är låst just nu.

Tillagd i version 3.14.

Konditionera objekt

En villkorsvariabel är alltid associerad med någon form av lås; detta kan anges eller så skapas ett som standard. Att skicka in ett lås är användbart när flera villkorsvariabler måste dela på samma lås. Låset är en del av villkorsobjektet: du behöver inte spåra det separat.

En villkorsvariabel följer context management protocol: genom att använda with-satsen förvärvas det associerade låset under hela det inneslutna blocket. Metoderna acquire() och release() anropar också motsvarande metoder för det associerade låset.

Andra metoder måste anropas med det associerade låset kvar. Metoden wait() frigör låset och blockerar sedan tills en annan tråd väcker det genom att anropa notify() eller notify_all(). När den har väckts återtar wait() låset och återgår. Det är också möjligt att ange en timeout.

Metoden notify() väcker en av de trådar som väntar på villkorsvariabeln, om det finns några som väntar. Metoden notify_all() väcker alla trådar som väntar på villkorsvariabeln.

Observera: metoderna notify() och notify_all() frigör inte låset; detta innebär att den tråd eller de trådar som väcks inte kommer att återvända från sitt anrop av wait() omedelbart, utan först när den tråd som anropade notify() eller notify_all() slutligen släpper äganderätten till låset.

Den typiska programmeringsstilen som använder villkorsvariabler använder låset för att synkronisera åtkomst till ett delat tillstånd; trådar som är intresserade av en viss förändring av tillståndet anropar wait() upprepade gånger tills de ser det önskade tillståndet, medan trådar som ändrar tillståndet anropar notify() eller notify_all() när de ändrar tillståndet på ett sådant sätt att det möjligen kan vara ett önskat tillstånd för en av de väntande. Följande kod är till exempel en generisk producent-konsument-situation med obegränsad buffertkapacitet:

# Konsumera ett föremål
med cv:
    while not an_item_is_available():
        cv.wait()
    hämta_ett_tillgängligt_objekt()

# Producera ett objekt
med cv:
    make_an_item_available()
    cv.notify()

while-loopen som kontrollerar applikationens villkor är nödvändig eftersom wait() kan returneras efter godtyckligt lång tid och det villkor som föranledde notify()-anropet kanske inte längre är sant. Detta är inbyggt i programmering med flera trådar. Metoden wait_for() kan användas för att automatisera villkorskontrollen och underlättar beräkningen av timeouts:

# Konsumera ett föremål
med cv:
    cv.wait_for(an_item_is_available)
    hämta_ett_tillgängligt_objekt()

För att välja mellan notify() och notify_all() bör du överväga om en tillståndsändring kan vara intressant för endast en eller flera väntande trådar. I en typisk producent-konsument-situation behöver t.ex. en konsumenttråd bara väckas om ett objekt läggs till i bufferten.

class threading.Condition(lock=None)

Denna klass implementerar objekt för villkorsvariabler. En villkorsvariabel tillåter en eller flera trådar att vänta tills de får ett meddelande från en annan tråd.

Om argumentet lock anges och inte None, måste det vara ett Lock- eller RLock-objekt, och det används som underliggande lås. Annars skapas ett nytt RLock-objekt som används som det underliggande låset.

Ändrad i version 3.3: ändrades från en fabriksfunktion till en klass.

acquire(*args)

Förvärva det underliggande låset. Denna metod anropar motsvarande metod på det underliggande låset; returvärdet är vad den metoden returnerar.

release()

Frigör det underliggande låset. Denna metod anropar motsvarande metod på det underliggande låset; det finns inget returvärde.

locked()

Returnerar en boolean som anger om detta objekt är låst just nu.

Tillagd i version 3.14.

wait(timeout=None)

Vänta tills du blir meddelad eller tills en timeout inträffar. Om den anropande tråden inte har förvärvat låset när denna metod anropas, kommer ett RuntimeError att uppstå.

Denna metod frigör det underliggande låset och blockerar sedan tills den väcks av ett notify()- eller notify_all()-anrop för samma tillståndsvariabel i en annan tråd, eller tills den valfria timeouten inträffar. När den har väckts eller fått timeout återtar den låset och återvänder.

När argumentet timeout finns med och inte None, ska det vara ett flyttal som anger en tidsgräns för operationen i sekunder (eller bråkdelar därav).

När det underliggande låset är ett RLock frigörs det inte med hjälp av dess release()-metod, eftersom detta kanske inte låser upp låset när det har förvärvats flera gånger rekursivt. Istället används ett internt gränssnitt för klassen RLock, som verkligen låser upp det även om det har förvärvats rekursivt flera gånger. Ett annat internt gränssnitt används sedan för att återställa rekursionsnivån när låset förvärvas på nytt.

Returvärdet är True om inte en given timeout har löpt ut, i vilket fall det är False.

Ändrad i version 3.2: Tidigare returnerade metoden alltid None.

wait_for(predicate, timeout=None)

Vänta tills ett villkor utvärderas till sant. predicate ska vara en callable vars resultat kommer att tolkas som ett booleskt värde. En timeout kan anges som ger den maximala tiden att vänta.

Denna verktygsmetod kan anropa wait() upprepade gånger tills predikatet är uppfyllt eller tills en timeout inträffar. Returvärdet är det sista returvärdet för predikatet och kommer att utvärderas till False om metoden tidsavbröts.

Om man bortser från timeout-funktionen motsvarar anrop av denna metod ungefär att skriva:

while not predicate():
    cv.vänta()

Därför gäller samma regler som för wait(): Låset måste hållas när det anropas och återfås när det returneras. Predikatet utvärderas med låset kvar.

Tillagd i version 3.2.

notify(n=1)

Som standard väcks en tråd som väntar på detta villkor, om det finns någon. Om den anropande tråden inte har förvärvat låset när denna metod anropas, kommer ett RuntimeError att uppstå.

Den här metoden väcker högst n av de trådar som väntar på villkorvariabeln; den är ingen operation om inga trådar väntar.

Den nuvarande implementationen väcker exakt n trådar om minst n trådar väntar. Det är dock inte säkert att förlita sig på detta beteende. En framtida, optimerad implementering kan ibland väcka fler än n trådar.

Notera: en väckt tråd återvänder inte från sitt wait()-anrop förrän den kan återta låset. Eftersom notify() inte släpper låset, bör dess anropare göra det.

notify_all()

Väck alla trådar som väntar på detta villkor. Denna metod fungerar som notify(), men väcker alla väntande trådar istället för en. Om den anropande tråden inte har förvärvat låset när denna metod anropas, kommer ett RuntimeError att uppstå.

Metoden notifyAll är ett föråldrat alias för denna metod.

Semaför-objekt

Detta är en av de äldsta synkroniseringsprimitiverna i datavetenskapens historia, uppfunnen av den tidiga holländska datavetaren Edsger W. Dijkstra (han använde namnen P() och V() istället för acquire() och release()).

En semafor hanterar en intern räknare som decimeras vid varje anrop av acquire() och ökas vid varje anrop av release(). Räknaren kan aldrig gå under noll; när acquire() upptäcker att den är noll blockerar den och väntar tills någon annan tråd anropar release().

Semaforer stöder också context management protocol.

class threading.Semaphore(value=1)

Denna klass implementerar semaforobjekt. En semafor hanterar en atomisk räknare som representerar antalet release()-anrop minus antalet acquire()-anrop, plus ett initialt värde. Metoden acquire() blockerar om det behövs tills den kan återvända utan att räknaren blir negativ. Om value inte anges är standardvärdet 1.

Det valfria argumentet anger det initiala värdet för den interna räknaren; standardvärdet är 1. Om det angivna värdet är mindre än 0, uppstår ValueError.

Ändrad i version 3.3: ändrades från en fabriksfunktion till en klass.

acquire(blocking=True, timeout=None)

Förvärva en semafor.

När den anropas utan argument:

  • Om den interna räknaren är större än noll vid inmatningen, dekrementera den med ett och returnera True omedelbart.

  • Om den interna räknaren är noll vid inmatningen, blockera tills den väcks genom ett anrop till release(). När du har väckts (och räknaren är större än 0), dekrementera räknaren med 1 och returnera True. Exakt en tråd kommer att väckas vid varje anrop till release(). Ordningen i vilken trådarna väcks bör inte förlitas på.

Blockera inte när den anropas med blocking satt till False. Om ett anrop utan argument skulle blockera, returnera False omedelbart; i annat fall, gör samma sak som vid anrop utan argument och returnera True.

När den anropas med en timeout annan än None, kommer den att blockera i högst timeout sekunder. Om förvärvet inte slutförs framgångsrikt inom detta intervall returneras False. Returnera annars True.

Ändrad i version 3.2: Parametern timeout är ny.

release(n=1)

Släpp en semafor och öka den interna räknaren med n. När den var noll vid inmatningen och andra trådar väntar på att den ska bli större än noll igen, väcker du n av dessa trådar.

Ändrad i version 3.9: Lagt till parametern n för att släppa flera väntande trådar samtidigt.

class threading.BoundedSemaphore(value=1)

Klass som implementerar begränsade semaforobjekt. En bounded semaphore kontrollerar att dess aktuella värde inte överstiger dess initiala värde. Om så är fallet, genereras ValueError. I de flesta situationer används semaforer för att bevaka resurser med begränsad kapacitet. Om semaforen släpps för många gånger är det ett tecken på en bugg. Om värde inte anges är standardvärdet 1.

Ändrad i version 3.3: ändrades från en fabriksfunktion till en klass.

Semaphore exempel

Semaforer används ofta för att bevaka resurser med begränsad kapacitet, t.ex. en databasserver. I alla situationer där resursens storlek är fast bör du använda en begränsad semafor. Innan du skapar några arbetstrådar skulle din huvudtråd initiera semaforen:

maxanslutningar = 5
# ...
pool_sema = BoundedSemaphore(värde=maxconnections)

När de har skapats anropar arbetstrådarna semaforens metoder för att förvärva och frigöra när de behöver ansluta till servern:

med pool_sema:
    conn = connectdb()
    försöker:
        # ... använd anslutning ...
    slutligen: # ..:
        conn.close()

Användningen av en begränsad semafor minskar risken för att ett programmeringsfel som gör att semaforen släpps mer än den förvärvas inte upptäcks.

Händelseobjekt

Detta är en av de enklaste mekanismerna för kommunikation mellan trådar: en tråd signalerar en händelse och andra trådar väntar på den.

Ett eventobjekt hanterar en intern flagga som kan sättas till true med metoden set() och återställas till false med metoden clear(). Metoden wait() blockerar tills flaggan är sann.

class threading.Event

Klass som implementerar händelseobjekt. En händelse hanterar en flagga som kan sättas till true med metoden set() och återställas till false med metoden clear(). Metoden wait() blockerar tills flaggan är sann. Flaggan är initialt falsk.

Ändrad i version 3.3: ändrades från en fabriksfunktion till en klass.

is_set()

Returnerar True om och endast om den interna flaggan är sann.

Metoden isSet är ett föråldrat alias för denna metod.

set()

Sätt den interna flaggan till true. Alla trådar som väntar på att den ska bli sann väcks. Trådar som anropar wait() när flaggan är true kommer inte att blockera alls.

clear()

Återställer den interna flaggan till false. Därefter kommer trådar som anropar wait() att blockeras tills set() anropas för att sätta den interna flaggan till true igen.

wait(timeout=None)

Blockerar så länge som den interna flaggan är falsk och timeouten, om en sådan har angetts, inte har löpt ut. Returvärdet representerar anledningen till att denna blockeringsmetod returnerades; True om den returneras eftersom den interna flaggan är satt till true, eller False om en timeout ges och den interna flaggan inte blev true inom den givna väntetiden.

När timeout-argumentet finns och inte är None, ska det vara ett flyttal som anger en timeout för operationen i sekunder eller bråkdelar därav.

Ändrad i version 3.1: Tidigare returnerade metoden alltid None.

Timer-objekt

Den här klassen representerar en åtgärd som ska utföras först efter att en viss tid har gått — en timer. Timer är en underklass till Thread och fungerar som sådan också som ett exempel på hur man skapar egna trådar.

Timers startas, precis som trådar, genom att anropa deras metod Timer.start. Timern kan stoppas (innan dess åtgärd har påbörjats) genom att anropa metoden cancel(). Det intervall som timern väntar på innan den utför sin åtgärd behöver inte vara exakt detsamma som det intervall som anges av användaren.

Till exempel:

def hello():
    print("hej, världen")

t = Timer(30.0, hallå)
t.start() # efter 30 sekunder kommer "hello, world" att skrivas ut
class threading.Timer(interval, function, args=None, kwargs=None)

Skapa en timer som kör function med argumenten args och nyckelordsargumenten kwargs, efter att interval sekunder har passerat. Om args är None (standard) kommer en tom lista att användas. Om kwargs är None (standard) kommer en tom dict att användas.

Ändrad i version 3.3: ändrades från en fabriksfunktion till en klass.

cancel()

Stoppa timern och avbryt utförandet av timerns åtgärd. Detta fungerar bara om timern fortfarande befinner sig i vänteläge.

Barriärobjekt

Tillagd i version 3.2.

Denna klass tillhandahåller en enkel synkroniseringsprimitiv för användning av ett fast antal trådar som behöver vänta på varandra. Var och en av trådarna försöker passera barriären genom att anropa metoden wait() och blockerar tills alla trådar har gjort sina anrop till wait(). Vid denna punkt släpps trådarna samtidigt.

Barriären kan återanvändas ett obegränsat antal gånger för samma antal trådar.

Som ett exempel följer här ett enkelt sätt att synkronisera en klient- och servertråd:

b = Barriär(2, timeout=5)

def server():
    start_server()
    b.wait()
    while True:
        anslutning = acceptera_anslutning()
        process_server_connection(anslutning)

def klient():
    b.wait()
    medan True:
        anslutning = make_connection()
        process_client_connection(anslutning)
class threading.Barrier(parties, action=None, timeout=None)

Skapa ett barriärobjekt för parties antal trådar. En action, när den tillhandahålls, är en callable som ska anropas av en av trådarna när de släpps. timeout är standardvärdet för timeout om inget anges för metoden wait().

wait(timeout=None)

Passera barriären. När alla trådar som är parter i barriären har anropat denna funktion släpps de samtidigt. Om en timeout anges används den i stället för den som angavs i klassens konstruktor.

Returvärdet är ett heltal i intervallet 0 till parties – 1, olika för varje tråd. Detta kan användas för att välja en tråd för att göra några speciella hushållsarbeten, t.ex.:

i = barriär.vänta()
if i == 0:
    # Endast en tråd behöver skriva ut detta
    print("passerade barriären")

Om en action tillhandahölls till konstruktören kommer en av trådarna att ha anropat den innan den släpps. Om detta anrop ger upphov till ett fel, försätts barriären i det brutna tillståndet.

Om anropet tidsbegränsas försätts barriären i ett trasigt tillstånd.

Denna metod kan ge upphov till ett BrokenBarrierError undantag om barriären bryts eller återställs medan en tråd väntar.

reset()

Återställer barriären till det tomma standardtillståndet. Alla trådar som väntar på den kommer att få undantaget BrokenBarrierError.

Observera att denna funktion kan kräva viss extern synkronisering om det finns andra trådar vars tillstånd är okänt. Om en barriär bryts kan det vara bättre att bara lämna den och skapa en ny.

abort()

Sätter barriären i ett trasigt tillstånd. Detta gör att alla aktiva eller framtida anrop till wait() misslyckas med BrokenBarrierError. Använd detta till exempel om en av trådarna behöver avbrytas för att undvika att applikationen låser sig.

Det kan vara att föredra att helt enkelt skapa barriären med ett vettigt timeout-värde för att automatiskt skydda sig mot att en av trådarna går fel.

parties

Det antal trådar som krävs för att passera barriären.

n_waiting

Antalet trådar som för närvarande väntar i barriären.

broken

En boolean som är True om barriären är i ett trasigt tillstånd.

exception threading.BrokenBarrierError

Detta undantag, en underklass till RuntimeError, uppstår när objektet Barrier återställs eller bryts.

Använda lås, villkor och semaforer i with-satsen

Alla objekt som tillhandahålls av denna modul och som har metoderna acquire och release kan användas som kontexthanterare för en with-sats. Metoden acquire kommer att anropas när blocket skrivs in och release kommer att anropas när blocket skrivs ut. Därav följande utdrag:

med något_lås:
    # gör något...

är likvärdig med:

some_lock.acquire()
försök:
    # gör något...
slutligen:
    some_lock.release()

För närvarande kan objekten Lock, RLock, Condition, Semaphore och BoundedSemaphore användas som with statement context managers.