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ör stdout och stderr (om subprocess.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ör stdout och stderr (om subprocess.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 av StreamWriter.

Om PIPE skickas till argumenten stdout eller stderr kommer attributen Process.stdout och Process.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() och create_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:

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 eller stderr=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 metoden communicate() när du använder pipes för att undvika detta tillstånd.

async communicate(input=None)

Interagera med processen:

  1. skicka data till stdin (om input inte är None);

  2. stänger stdin;

  3. läser data från stdout och stderr tills EOF nås;

  4. 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 eller ConnectionResetError 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 än None i resultattupeln, måste processen skapas med stdout=PIPE och/eller stderr=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ör terminate(). CTRL_C_EVENT och CTRL_BREAK_EVENT kan skickas till processer som startats med en creationflags-parameter som inkluderar CREATE_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) eller None om processen skapades med stdin=None.

stdout

Standardutdataström (StreamReader) eller None om processen skapades med stdout=None.

stderr

Standardfelström (StreamReader) eller None om processen skapades med stderr=None.

Varning

Använd metoden communicate() i stället för process.stdin.write(), await process.stdout.read() eller await 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 signal N (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.

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å.