Synkroniseringsprimitiver¶
Källkod: Lib/asyncio/locks.py
asyncios synkroniseringsprimitiver är utformade för att likna dem i modulen threading
med två viktiga förbehåll:
asyncioprimitiver är inte trådsäkra, därför bör de inte användas för synkronisering av OS-trådar (använd
threading
för det);metoderna för dessa synkroniseringsprimitiver accepterar inte argumentet timeout; använd funktionen
asyncio.wait_for()
för att utföra operationer med timeouts.
asyncio har följande grundläggande synkroniseringsprimitiver:
Lås¶
- class asyncio.Lock¶
Implementerar ett mutex-lås för asyncio-uppgifter. Inte tråd-säker.
Ett asynciolås kan användas för att garantera exklusiv tillgång till en delad resurs.
Det föredragna sättet att använda ett Lock är en
async with
-sats:lock = asyncio.Lock() # ... later async with lock: # access shared state
vilket är likvärdigt med:
lock = asyncio.Lock() # ... later await lock.acquire() try: # access shared state finally: lock.release()
Ändrad i version 3.10: Parametern loop har tagits bort.
- async acquire()¶
Förvärva låset.
Den här metoden väntar tills låset är unlocked, sätter det till locked och returnerar
True
.När mer än en coroutine blockeras i
acquire()
i väntan på att låset ska låsas upp, fortsätter bara en coroutine till slut.Att förvärva ett lås är rättvist: den coroutine som fortsätter kommer att vara den första coroutine som började vänta på låset.
- release()¶
Lossa låset.
När låset är locked, återställ det till unlocked och returnera.
Om låset är olåst uppstår ett
RuntimeError
.
- locked()¶
Returnerar
True
om låset är locked.
Event¶
- class asyncio.Event¶
Ett händelseobjekt. Inte tråd-säkert.
En asynciohändelse kan användas för att meddela flera asynciouppgifter att en händelse har inträffat.
Ett Event-objekt hanterar en intern flagga som kan sättas till true med metoden
set()
och återställas till false med metodenclear()
. Metodenwait()
blockerar tills flaggan är satt till true. Flaggan är initialt satt till false.Ändrad i version 3.10: Parametern loop har tagits bort.
Exempel:
async def waiter(event): print('waiting for it ...') await event.wait() print('... got it!') async def main(): # Create an Event object. event = asyncio.Event() # Spawn a Task to wait until 'event' is set. waiter_task = asyncio.create_task(waiter(event)) # Sleep for 1 second and set the event. await asyncio.sleep(1) event.set() # Wait until the waiter task is finished. await waiter_task asyncio.run(main())
- async wait()¶
Vänta tills händelsen är inställd.
Om händelsen är inställd, returnera
True
omedelbart. Annars blockeras tills en annan uppgift anroparset()
.
- set()¶
Ställ in händelsen.
Alla uppgifter som väntar på att händelsen ska aktiveras kommer omedelbart att väckas.
- clear()¶
Rensa (avmarkera) händelsen.
Efterföljande uppgifter som väntar på
wait()
kommer nu att blockeras tills metodenset()
anropas igen.
- is_set()¶
Returnerar
True
om händelsen är inställd.
Villkor¶
- class asyncio.Condition(lock=None)¶
Ett Condition-objekt. Inte tråd-säkert.
En asyncio-villkorsprimitiv kan användas av en uppgift för att vänta på att en händelse ska inträffa och sedan få exklusiv tillgång till en delad resurs.
I huvudsak kombinerar ett Condition-objekt funktionaliteten hos en
Event
och enLock
. Det är möjligt att låta flera Condition-objekt dela ett Lock, vilket gör det möjligt att samordna exklusiv tillgång till en delad resurs mellan olika uppgifter som är intresserade av särskilda tillstånd för den delade resursen.Det valfria lock-argumentet måste vara ett
Lock
-objekt ellerNone
. I det senare fallet skapas ett nytt Lock-objekt automatiskt.Ändrad i version 3.10: Parametern loop har tagits bort.
Det föredragna sättet att använda ett villkor är en
async with
-sats:cond = asyncio.Condition() # ... later async with cond: await cond.wait()
vilket är likvärdigt med:
cond = asyncio.Condition() # ... later await cond.acquire() try: await cond.wait() finally: cond.release()
- async acquire()¶
Förvärva det underliggande låset.
Denna metod väntar tills det underliggande låset är unlocked, sätter det till locked och returnerar
True
.
- notify(n=1)¶
Väck n uppgifter (1 som standard) som väntar på detta villkor. Om färre än n uppgifter väntar väcks de alla.
Låset måste förvärvas innan denna metod anropas och släppas kort därefter. Om metoden anropas med ett olåst lås kommer ett
RuntimeError
-fel att uppstå.
- locked()¶
Returnerar
True
om det underliggande låset är förvärvat.
- notify_all()¶
Väck alla uppgifter som väntar på detta villkor.
Den här metoden fungerar som
notify()
, men väcker alla väntande uppgifter.Låset måste förvärvas innan denna metod anropas och släppas kort därefter. Om metoden anropas med ett olåst lås kommer ett
RuntimeError
-fel att uppstå.
- release()¶
Lossa det underliggande låset.
När den anropas på ett olåst lås uppstår ett
RuntimeError
.
- async wait()¶
Vänta tills du får besked.
Om den anropande uppgiften inte har förvärvat låset när denna metod anropas, uppstår ett
RuntimeError
.Den här metoden frigör det underliggande låset och blockerar sedan tills den väcks av ett anrop från
notify()
ellernotify_all()
. När den har väckts återtar Condition sitt lås och denna metod returnerarTrue
.Observera att en uppgift kan återvända från detta anrop på ett felaktigt sätt, vilket är anledningen till att anroparen alltid bör kontrollera tillståndet igen och vara beredd att
wait()
igen. Av denna anledning kanske du föredrar att användawait_for()
istället.
Semafor¶
- class asyncio.Semaphore(value=1)¶
Ett semaforobjekt. Inte tråd-säkert.
En semafor hanterar en intern räknare som decimeras vid varje anrop av
acquire()
och ökas vid varje anrop avrelease()
. Räknaren kan aldrig gå under noll; näracquire()
upptäcker att den är noll blockeras den och väntar tills någon uppgift anroparrelease()
.Det valfria argumentet value anger det initiala värdet för den interna räknaren (
1
som standard). Om det angivna värdet är mindre än0
uppstår ettValueError
.Ändrad i version 3.10: Parametern loop har tagits bort.
Det föredragna sättet att använda en semafor är en
async with
-sats:sem = asyncio.Semaphore(10) # ... later async with sem: # work with shared resource
vilket är likvärdigt med:
sem = asyncio.Semaphore(10) # ... later await sem.acquire() try: # work with shared resource finally: sem.release()
- async acquire()¶
Förvärva en semafor.
Om den interna räknaren är större än noll, decimera den med ett och returnera
True
omedelbart. Om den är noll, vänta tills enrelease()
anropas och returneraTrue
.
- locked()¶
Returnerar
True
om semaforen inte kan förvärvas omedelbart.
- release()¶
Frigör en semafor, vilket ökar den interna räknaren med ett steg. Kan väcka en uppgift som väntar på att förvärva semaforen.
Till skillnad från
BoundedSemaphore
tillåterSemaphore
flerrelease()
-anrop änacquire()
-anrop.
BoundedSemaphore¶
- class asyncio.BoundedSemaphore(value=1)¶
Ett avgränsat semaforobjekt. Inte tråd-säkert.
Bounded Semaphore är en version av
Semaphore
som ger upphov till ettValueError
irelease()
om den ökar den interna räknaren över det ursprungliga värdet.Ändrad i version 3.10: Parametern loop har tagits bort.
Barrier¶
- class asyncio.Barrier(parties)¶
Ett barriärobjekt. Inte tråd-säkert.
En barriär är en enkel synkroniseringsprimitiv som gör det möjligt att blockera tills parties antal uppgifter väntar på den. Uppgifter kan vänta på
wait()
-metoden och blockeras tills det angivna antalet uppgifter slutar vänta påwait()
. Vid den tidpunkten kommer alla väntande uppgifter att avblockeras samtidigt.async with
kan användas som ett alternativ till att vänta påwait()
.Barriären kan återanvändas ett obegränsat antal gånger.
Exempel:
async def example_barrier(): # barrier with 3 parties b = asyncio.Barrier(3) # create 2 new waiting tasks asyncio.create_task(b.wait()) asyncio.create_task(b.wait()) await asyncio.sleep(0) print(b) # The third .wait() call passes the barrier await b.wait() print(b) print("barrier passed") await asyncio.sleep(0) print(b) asyncio.run(example_barrier())
Resultatet av detta exempel är:
<asyncio.locks.Barrier object at 0x... [filling, waiters:2/3]> <asyncio.locks.Barrier object at 0x... [draining, waiters:0/3]> barrier passed <asyncio.locks.Barrier object at 0x... [filling, waiters:0/3]>
Tillagd i version 3.11.
- async wait()¶
Passera spärren. När alla uppgifter som är parter i barriären har anropat denna funktion, avblockeras alla samtidigt.
När en väntande eller blockerad uppgift i barriären avbryts, lämnar denna uppgift barriären som förblir i samma tillstånd. Om barriärens tillstånd är ”fyllning”, minskar antalet väntande uppgifter med 1.
Returvärdet är ett heltal i intervallet 0 till
parties-1
, olika för varje uppgift. Detta kan användas för att välja en uppgift för att göra några speciella hushållsarbeten, t.ex.:... async with barrier as position: if position == 0: # Only one task prints this print('End of *draining phase*')
Denna metod kan ge upphov till ett
BrokenBarrierError
undantag om barriären bryts eller återställs medan en uppgift väntar. Den kan ge upphov till ettCancelledError
om en uppgift avbryts.
- async reset()¶
Återställer barriären till standardtillståndet, tom. Alla uppgifter som väntar på den kommer att få undantaget
BrokenBarrierError
.Om en barriär är bruten kan det vara bättre att bara lämna den och skapa en ny.
- async abort()¶
Sätter barriären i ett trasigt tillstånd. Detta gör att alla aktiva eller framtida anrop till
wait()
misslyckas medBrokenBarrierError
. Använd detta till exempel om en av uppgifterna måste avbrytas, för att undvika oändligt väntande uppgifter.
- parties¶
Det antal uppgifter som krävs för att passera barriären.
- n_waiting¶
Antalet uppgifter som för närvarande väntar i barriären medan den fylls på.
- broken¶
En boolean som är
True
om barriären är i ett trasigt tillstånd.
- exception asyncio.BrokenBarrierError¶
Detta undantag, en underklass till
RuntimeError
, uppstår när objektetBarrier
återställs eller bryts.
Ändrad i version 3.9: Att förvärva ett lås med hjälp av await lock
eller yield from lock
och/eller with
-satsen (with await lock
, with (yield from lock)
) togs bort. Använd async with lock
istället.