concurrent.interpreters
— Flera tolkar i samma process¶
Tillagd i version 3.14.
Källkod: Lib/concurrent/interpreters
Modulen concurrent.interpreters
konstruerar gränssnitt på högre nivå ovanpå modulen _interpreters
på lägre nivå.
Modulen är främst avsedd att tillhandahålla ett grundläggande API för att hantera tolkar (även kallade ”undertolkar”) och köra saker i dem. Att köra saker innebär oftast att man växlar till en tolk (i den aktuella tråden) och anropar en funktion i det exekveringssammanhanget.
För samtidighet tillhandahåller tolkarna själva (och den här modulen) inte mycket mer än isolering, vilket i sig inte är användbart. Faktisk samtidighet är tillgänglig separat genom threads
Se under
Se även
InterpreterPoolExecutor
kombinerar trådar med tolkar i ett välbekant gränssnitt.
- Isolering av tilläggsmoduler
så här uppdaterar du en tilläggsmodul för att stödja flera tolkar
Tillgänglighet: not WASI.
Den här modulen fungerar inte eller är inte tillgänglig på WebAssembly. Se WebAssembly-plattformar för mer information.
Information om nyckel¶
Innan vi går vidare finns det ett antal detaljer att tänka på när det gäller att använda flera tolkar:
isolated, som standard
inga implicita trådar
inte alla PyPI-paket stöder användning i flera tolkar ännu
Introduktion¶
En ”tolk” är i själva verket exekveringskontexten för Pythons runtime. Den innehåller allt tillstånd som körtiden behöver för att exekvera ett program. Detta inkluderar saker som importstatus och builtins. (Varje tråd, även om det bara finns en huvudtråd, har lite extra körtidstillstånd, utöver den aktuella tolken, relaterat till det aktuella undantaget och bytecode eval-loopen)
Konceptet och funktionaliteten för tolken har varit en del av Python sedan version 2.2, men funktionen var endast tillgänglig via C-API och inte särskilt välkänd, och isoleringen var relativt ofullständig fram till version 3.12.
Flera tolkar och isolering¶
En Python-implementation kan stödja användning av flera tolkar i samma process. CPython har detta stöd. Varje tolk är effektivt isolerad från de andra (med ett begränsat antal noggrant hanterade processglobala undantag från regeln).
Denna isolering är främst användbar som en stark separation mellan distinkta logiska komponenter i ett program, där du vill ha noggrann kontroll över hur dessa komponenter interagerar.
Anteckning
Tolkar i samma process kan tekniskt sett aldrig vara strikt isolerade från varandra eftersom det finns få restriktioner för minnesåtkomst inom samma process. Pythons runtime gör sitt bästa för att isolera, men tilläggsmoduler kan lätt bryta mot detta. Använd därför inte flera tolkar i säkerhetskänsliga situationer, där de inte bör ha tillgång till varandras data.
Att köra in en tolk¶
Att köra i en annan tolk innebär att man växlar till den i den aktuella tråden och sedan anropar någon funktion. Runtime kommer att exekvera funktionen med hjälp av den aktuella tolkens tillstånd. Modulen concurrent.interpreters
tillhandahåller ett grundläggande API för att skapa och hantera tolkar, samt för att växla och anropa.
Inga andra trådar startas automatiskt för operationen. Det finns dock en hjälpare för det. Det finns en annan dedikerad hjälp för att anropa den inbyggda exec()
i en tolk.
När exec()
(eller eval()
) anropas i en tolk, körs de med tolkens __main__
-modul som ”globals”-namnrymd. Detsamma gäller för funktioner som inte är associerade med någon modul. Detta är samma sak som att skript som anropas från kommandoraden körs i modulen __main__
.
Samtidighet och parallellism¶
Som tidigare nämnts tillhandahåller tolkar inte någon samtidighet i sig själva. De representerar strikt den isolerade exekveringskontext som körtiden kommer att använda * i den aktuella tråden*. Denna isolering gör att de liknar processer, men de har fortfarande effektivitet i processen, precis som trådar.
Allt detta sagt, tolkar stöder naturligtvis vissa varianter av samtidighet. Det finns en kraftfull bieffekt av den isoleringen. Det möjliggör ett annat tillvägagångssätt för samtidighet än du kan ta med async eller trådar. Det är en liknande samtidighetsmodell som CSP eller aktormodellen, en modell som är relativt lätt att resonera om.
Du kan dra nytta av den här samtidighetsmodellen i en enda tråd genom att växla fram och tillbaka mellan tolkarna på samma sätt som Stackless. Den här modellen är dock mer användbar när du kombinerar tolkar med flera trådar. Detta innebär oftast att man startar en ny tråd, där man växlar till en annan tolk och kör det man vill där.
Varje faktisk tråd i Python, även om du bara kör i huvudtråden, har sin egen aktuella exekveringskontext. Flera trådar kan använda samma tolk eller olika.
På en hög nivå kan man tänka sig kombinationen av trådar och tolkar som trådar med opt-in-delning.
Som en betydande bonus är tolkarna tillräckligt isolerade för att de inte delar GIL, vilket innebär att kombinera trådar med flera tolkar möjliggör full parallellism med flera kärnor. (Detta har varit fallet sedan Python 3.12.)
Kommunikation mellan tolkar¶
I praktiken är flera tolkar bara användbara om vi har ett sätt att kommunicera mellan dem. Detta innebär vanligtvis någon form av meddelandepassning, men kan även innebära att data delas på något noggrant hanterat sätt.
Med detta i åtanke tillhandahåller modulen concurrent.interpreters
en implementation av queue.Queue
, tillgänglig via create_queue()
.
Referens¶
Denna modul definierar följande funktioner:
- concurrent.interpreters.list_all()¶
Returnerar en
list
avInterpreter
-objekt, ett för varje befintlig tolk.
- concurrent.interpreters.get_current()¶
Returnerar ett
Interpreter
-objekt för den tolk som körs för tillfället.
- concurrent.interpreters.get_main()¶
Returnerar ett
Interpreter
-objekt för huvudtolken. Detta är den tolk som körtiden skapade för att köra REPL eller det skript som gavs på kommandoraden. Det är vanligtvis den enda.
- concurrent.interpreters.create()¶
Initiera en ny (inaktiv) Python-tolk och returnera ett
Interpreter
-objekt för den.
- concurrent.interpreters.create_queue()¶
Initiera en ny tolköverskridande kö och returnera ett
Queue
-objekt för den.
Tolkningsobjekt¶
- class concurrent.interpreters.Interpreter(id)¶
En enda tolk i den aktuella processen.
Generellt sett bör inte
Interpreter
anropas direkt. Använd iställetcreate()
eller någon av de andra modulfunktionerna.- id¶
(skrivskyddad)
Den underliggande tolkens ID.
- whence¶
(skrivskyddad)
En sträng som beskriver varifrån tolken kommer.
- is_running()¶
Returnerar
True
om tolken för närvarande exekverar kod i sin__main__
-modul ochFalse
i annat fall.
- close()¶
Slutför och förstör tolken.
- prepare_main(ns=None, **kwargs)¶
Binda objekt i tolkens
__main__
-modul.Vissa objekt delas faktiskt och vissa kopieras på ett effektivt sätt, men de flesta kopieras via
pickle
. Se ”Delning” av objekt.
- exec(code, /, dedent=True)¶
Kör den angivna källkoden i tolken (i den aktuella tråden).
- call(callable, /, *args, **kwargs)¶
Returnerar resultatet av att anropa och köra den angivna funktionen i tolken (i den aktuella tråden).
- call_in_thread(callable, /, *args, **kwargs)¶
Kör den angivna funktionen i tolken (i en ny tråd).
Undantag¶
- exception concurrent.interpreters.InterpreterError¶
Detta undantag, som är en underklass till
Exception
, uppstår när ett tolkningsrelaterat fel inträffar.
- exception concurrent.interpreters.InterpreterNotFoundError¶
Detta undantag, som är en underklass till
InterpreterError
, uppstår när den avsedda tolken inte längre finns.
- exception concurrent.interpreters.ExecutionFailed¶
Detta undantag, som är en underklass till
InterpreterError
, uppstår när den löpande koden har orsakat ett undantag som inte fångats upp.- excinfo¶
En enkel ögonblicksbild av det undantag som uppstod i den andra tolken.
Detta undantag, som är en underklass till
TypeError
, uppstår när ett objekt inte kan skickas till en annan tolk.
Kommunikation mellan tolkar¶
- class concurrent.interpreters.Queue(id)¶
En wrapper runt en lågnivå, tolkningsöverskridande kö, som implementerar
queue.Queue
-gränssnittet. Den underliggande kön kan endast skapas genomcreate_queue()
.Vissa objekt delas faktiskt och vissa kopieras på ett effektivt sätt, men de flesta kopieras via
pickle
. Se ”Delning” av objekt.- id¶
(skrivskyddad)
Köns ID.
- exception concurrent.interpreters.QueueEmptyError¶
Detta undantag, en subklass av
queue.Empty
, uppstår frånQueue.get()
ochQueue.get_nowait()
när kön är tom.
- exception concurrent.interpreters.QueueFullError¶
Detta undantag, en subklass av
queue.Full
, uppstår frånQueue.put()
ochQueue.put_nowait()
när kön är full.
Grundläggande användning¶
Skapa en tolk och köra kod i den:
från samtidiga importtolkar
interp = tolkar.skapa()
# Kör i den aktuella OS-tråden.
interp.exec('print("spam!")')
interp.exec("""if True:
print('spam!')
""")
från textwrap import dedent
interp.exec(dedent("""
print('skräppost!')
"""))
def run(arg):
returnerar arg
res = interp.call(run, 'spam!')
print(res)
def run():
print('skräppost!')
interp.call(run)
# Kör i en ny OS-tråd.
t = interp.call_in_thread(run)
t.join()