Delprocesser¶
Källkod: Lib/asyncio/subprocess.py, Lib/asyncio/base_subprocess.py
I detta avsnitt beskrivs async/await asyncio API:er på hög nivå för att skapa och hantera underprocesser.
Här är ett exempel på hur asyncio kan köra ett shell-kommando och få resultatet av det:
import asyncio
async def run(cmd):
proc = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
print(f'[{cmd!r} exited with {proc.returncode}]')
if stdout:
print(f'[stdout]\n{stdout.decode()}')
if stderr:
print(f'[stderr]\n{stderr.decode()}')
asyncio.run(run('ls /zzz'))
kommer att skriva ut:
['ls /zzz' avslutades med 1]
[stderr]
ls: /zzz: Ingen sådan fil eller katalog
Eftersom alla asyncios subprocessfunktioner är asynkrona och asyncio tillhandahåller många verktyg för att arbeta med sådana funktioner, är det enkelt att köra och övervaka flera subprocesser parallellt. Det är faktiskt trivialt att modifiera ovanstående exempel för att köra flera kommandon samtidigt:
async def main():
await asyncio.gather(
run('ls /zzz'),
run('sleep 1; echo "hello"'))
asyncio.run(main())
Se även underavsnittet Exempel.
Skapa underprocesser¶
- async asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
Skapa en underprocess.
Argumentet limit anger buffertgränsen för
StreamReader
omslag förstdout
ochstderr
(omsubprocess.PIPE
skickas till argumenten stdout och stderr).Returnerar en
Process
-instans.Se dokumentationen för
loop.subprocess_exec()
för andra parametrar.Ändrad i version 3.10: Parametern loop har tagits bort.
- async asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
Kör skalkommandot cmd.
Argumentet limit anger buffertgränsen för
StreamReader
omslag förstdout
ochstderr
(omsubprocess.PIPE
skickas till argumenten stdout och stderr).Returnerar en
Process
-instans.Se dokumentationen för
loop.subprocess_shell()
för andra parametrar.Viktigt
Det är programmets ansvar att se till att alla blanksteg och specialtecken citeras på rätt sätt för att undvika shell injection-sårbarheter. Funktionen
shlex.quote()
kan användas för att på rätt sätt undkomma blanksteg och speciella skaltecken i strängar som ska användas för att konstruera skalkommandon.Ändrad i version 3.10: Parametern loop har tagits bort.
Anteckning
Underprocesser är tillgängliga för Windows om en ProactorEventLoop
används. Se Subprocessstöd på Windows för mer information.
Se även
asyncio har även följande lågnivå API:er för att arbeta med subprocesser: loop.subprocess_exec()
, loop.subprocess_shell()
, loop.connect_read_pipe()
, loop.connect_write_pipe()
, samt Subprocess Transports och Subprocess Protocols.
Konstanter¶
- asyncio.subprocess.PIPE¶
Kan skickas till parametrarna stdin, stdout eller stderr.
Om PIPE skickas till argumentet stdin kommer attributet
Process.stdin
att peka på en instans avStreamWriter
.Om PIPE skickas till argumenten stdout eller stderr kommer attributen
Process.stdout
ochProcess.stderr
att peka påStreamReader
-instanser.
- asyncio.subprocess.STDOUT¶
Specialvärde som kan användas som argumentet stderr och som anger att standardfelet ska omdirigeras till standardutmatningen.
- asyncio.subprocess.DEVNULL¶
Specialvärde som kan användas som stdin-, stdout- eller stderr-argument i processskapande funktioner. Det anger att specialfilen
os.devnull
kommer att användas för motsvarande subprocessström.
Interagera med underprocesser¶
Både funktionerna create_subprocess_exec()
och create_subprocess_shell()
returnerar instanser av klassen Process. Process är ett omslag på hög nivå som gör det möjligt att kommunicera med subprocesser och övervaka att de slutförs.
- class asyncio.subprocess.Process¶
Ett objekt som omsluter OS-processer som skapats av funktionerna
create_subprocess_exec()
ochcreate_subprocess_shell()
.Denna klass är utformad för att ha ett liknande API som klassen
subprocess.Popen
, men det finns några anmärkningsvärda skillnader:till skillnad från Popen har Process-instanser ingen motsvarighet till metoden
poll()
;metoderna
communicate()
ochwait()
har ingen parameter timeout: använd funktionenwait_for()
;metoden
Process.wait()
är asynkron, medan metodensubprocess.Popen.wait()
implementeras som en blockerande busy loop;parametern universal_newlines stöds inte.
Den här klassen är inte trådsäker.
Se även avsnittet Subprocesser och trådar.
- async wait()¶
Vänta tills barnprocessen har avslutats.
Ange och returnera attributet
returncode
.Anteckning
Den här metoden kan leda till dödläge när
stdout=PIPE
ellerstderr=PIPE
används och barnprocessen genererar så mycket utdata att den blockeras i väntan på att OS-pipebufferten ska ta emot mer data. Använd metodencommunicate()
när du använder pipes för att undvika detta tillstånd.
- async communicate(input=None)¶
Interagera med processen:
skicka data till stdin (om input inte är
None
);stänger stdin;
läser data från stdout och stderr tills EOF nås;
vänta på att processen ska avslutas.
Det valfria argumentet input är de data (
bytes
-objekt) som ska skickas till underordnad process.Returnera en tupel
(stdout_data, stderr_data)
.Om något av undantagen
BrokenPipeError
ellerConnectionResetError
uppstår när input skrivs in i stdin, ignoreras undantaget. Detta tillstånd inträffar när processen avslutas innan alla data har skrivits in i stdin.Om man vill skicka data till processens stdin, måste processen skapas med
stdin=PIPE
. På samma sätt, för att få något annat änNone
i resultattupeln, måste processen skapas medstdout=PIPE
och/ellerstderr=PIPE
argument.Observera att de data som läses buffras i minnet, så använd inte den här metoden om datastorleken är stor eller obegränsad.
Ändrad i version 3.12: stdin stängs även när
input=None
.
- send_signal(signal)¶
Skickar signalen signal till den underordnade processen.
Anteckning
I Windows är
SIGTERM
ett alias förterminate()
.CTRL_C_EVENT
ochCTRL_BREAK_EVENT
kan skickas till processer som startats med en creationflags-parameter som inkluderarCREATE_NEW_PROCESS_GROUP
.
- terminate()¶
Stoppa barnprocessen.
På POSIX-system skickar den här metoden
SIGTERM
till barnprocessen.I Windows anropas Win32 API-funktionen
TerminateProcess()
för att stoppa underordnad process.
- kill()¶
Avsluta barnprocessen.
På POSIX-system skickar den här metoden
SIGKILL
till barnprocessen.I Windows är denna metod ett alias för
terminate()
.
- stdin¶
Standardinmatningsström (
StreamWriter
) ellerNone
om processen skapades medstdin=None
.
- stdout¶
Standardutdataström (
StreamReader
) ellerNone
om processen skapades medstdout=None
.
- stderr¶
Standardfelström (
StreamReader
) ellerNone
om processen skapades medstderr=None
.
Varning
Använd metoden
communicate()
i stället förprocess.stdin.write()
,await process.stdout.read()
ellerawait process.stderr.read()
. På så sätt undviks dödlägen på grund av att strömmar pausar läsning eller skrivning och blockerar barnprocessen.- pid¶
Processens identifikationsnummer (PID).
Observera att för processer som skapats av funktionen
create_subprocess_shell()
är detta attribut PID för det skapade skalet.
- returncode¶
Processens returkod när den avslutas.
Ett värde på
None
anger att processen inte har avslutats ännu.Ett negativt värde
-N
anger att barnet avslutades med signalN
(endast POSIX).
Underprocesser och trådar¶
Standard asyncio event loop stöder som standard att köra subprocesser från olika trådar.
I Windows tillhandahålls underprocesser endast av ProactorEventLoop
(standard), SelectorEventLoop
har inget stöd för underprocesser.
Observera att alternativa implementeringar av händelseslingor kan ha egna begränsningar; se deras dokumentation.
Se även
Avsnittet Concurrency och multithreading i asyncio.
Exempel¶
Ett exempel där klassen Process
används för att styra en subprocess och klassen StreamReader
för att läsa från dess standardutdata.
Subprocessen skapas med funktionen create_subprocess_exec()
:
import asyncio
import sys
async def get_date():
code = 'import datetime; print(datetime.datetime.now())'
# Create the subprocess; redirect the standard output
# into a pipe.
proc = await asyncio.create_subprocess_exec(
sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
# Read one line of output.
data = await proc.stdout.readline()
line = data.decode('ascii').rstrip()
# Wait for the subprocess exit.
await proc.wait()
return line
date = asyncio.run(get_date())
print(f"Current date: {date}")
Se även samme exempel skrivet med hjälp av API:er på låg nivå.