Subprocessos¶
Código-fonte: Lib/asyncio/subprocess.py, Lib/asyncio/base_subprocess.py
Esta seção descreve APIs async/await asyncio de alto nível para criar e gerenciar subprocessos.
Aqui está um exemplo de como asyncio pode executar um comando shell e obter o seu resultado:
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'))
irá exibir:
['ls /zzz' exited with 1]
[stderr]
ls: /zzz: No such file or directory
Devido ao fato que todas as funções de subprocessos asyncio são assíncronas e asyncio fornece muitas ferramentas para trabalhar com tais funções, é fácil executar e monitorar múltiplos subprocessos em paralelo. É na verdade trivial modificar o exemplo acima para executar diversos comandos simultaneamente:
async def main():
await asyncio.gather(
run('ls /zzz'),
run('sleep 1; echo "hello"'))
asyncio.run(main())
Veja também a subseção Exemplos.
Criando subprocessos¶
-
coroutine
asyncio.
create_subprocess_exec
(program, *args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)¶ Cria um subprocesso.
O argumento limit define o limite do buffer para os wrappers
StreamReader
paraProcess.stdout
eProcess.stderr
(sesubprocess.PIPE
for passado para os argumentos stdout e stderr).Retorna uma instância de
Process
.Veja a documentação de
loop.subprocess_exec()
para outros parâmetros.Deprecated since version 3.8, will be removed in version 3.10: O parâmetro loop.
-
coroutine
asyncio.
create_subprocess_shell
(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)¶ Executa o comando cmd no shell.
O argumento limit define o limite do buffer para os wrappers
StreamReader
paraProcess.stdout
eProcess.stderr
(sesubprocess.PIPE
for passado para os argumentos stdout e stderr).Retorna uma instância de
Process
.Veja a documentação de
loop.subprocess_shell()
para outros parâmetros.Importante
É responsabilidade da aplicação garantir que todos os espaços em branco e caracteres especiais tenham aspas apropriadamente para evitar vulnerabilidades de injeção de shell. A função
shlex.quote()
pode ser usada para escapar espaços em branco e caracteres especiais de shell apropriadamente em strings que serão usadas para construir comandos shell.Deprecated since version 3.8, will be removed in version 3.10: O parâmetro loop.
Nota
Subprocesses are available for Windows if a ProactorEventLoop
is
used. See Subprocess Support on Windows
for details.
Ver também
asyncio também tem as seguintes APIs de baixo nível para trabalhar com subprocessos: loop.subprocess_exec()
, loop.subprocess_shell()
, loop.connect_read_pipe()
, loop.connect_write_pipe()
, assim como os Transportes de Subprocesso e Protocolos de Subprocesso.
Constantes¶
-
asyncio.subprocess.
PIPE
¶ Pode ser passado para os parâmetros stdin, stdout ou stderr.
Se PIPE for passado para o argumento stdin, o atributo
Process.stdin
irá apontar para uma instânciaStreamWriter
.Se PIPE for passado para os argumentos stdout ou stderr, os atributos
Process.stdout
eProcess.stderr
irão apontar para instânciasStreamReader
.
-
asyncio.subprocess.
STDOUT
¶ Valor especial que pode ser usado como o argumento stderr e indica que a saída de erro padrão deve ser redirecionada para a saída padrão.
-
asyncio.subprocess.
DEVNULL
¶ Valor especial que pode ser usado como argumento stdin, stdout ou stderr para funções de criação de processos. Ele indica que o arquivo especial
os.devnull
será usado para o fluxo de subprocesso correspondente.
Interagindo com subprocessos¶
Ambas as funções create_subprocess_exec()
e create_subprocess_shell()
retornam instâncias da classe Process. Process é um wrapper de alto nível que permite a comunicação com subprocessos e observar eles serem completados.
-
class
asyncio.subprocess.
Process
¶ Um objeto que envolve processos do sistema operacional criados pelas funções
create_subprocess_exec()
ecreate_subprocess_shell()
.Esta classe é projetada para ter uma API similar a classe
subprocess.Popen
, mas existem algumas diferenças notáveis:ao contrário de Popen, instâncias de Process não têm um equivalente ao método
poll()
;os métodos
communicate()
ewait()
não têm um parâmetro timeout: utilize a funçãowait_for()
;o método
Process.wait()
é assíncrono, enquanto que o métodosubprocess.Popen.wait()
é implementado como um laço bloqueante para indicar que está ocupado;o parâmetro universal_newlines não é suportado.
Esta classe não é seguro para thread.
Veja também a seção Subprocesso e Threads.
-
coroutine
wait
()¶ Aguarda o processo filho encerrar.
Define e retorna o atributo
returncode
.Nota
Este método pode entrar em deadlock ao usar
stdout=PIPE
oustderr=PIPE
e o processo filho gera tantas saídas que ele bloqueia a espera pelo encadeamento de buffer do sistema operacional para aceitar mais dados. Use o métodocommunicate()
ao usar encadeamentos para evitar essa condição.
-
coroutine
communicate
(input=None)¶ Interage com processo:
envia dados para stdin (se input for diferente de
None
);lê dados a partir de stdout e stderr, até que EOF (fim do arquivo) seja atingido;
aguarda o processo encerrar.
O argumento opcional input é a informação (objeto
bytes
) que será enviada para o processo filho.Retorna uma tupla
(stdout_data, stderr_data)
.Se qualquer exceção
BrokenPipeError
ouConnectionResetError
for levantada ao escrever input em stdin, a exceção é ignorada. Esta condição ocorre quando o processo encerra antes de todos os dados serem escritos em stdin.Se for desejado enviar dados para o stdin do processo, o mesmo precisa ser criado com
stdin=PIPE
. De forma similar, para obter qualquer coisa além deNone
na tupla resultante, o processo precisa ser criado com os argumentosstdout=PIPE
e/oustderr=PIPE
.Perceba que, os dados lidos são armazenados em um buffer na memória, então não use este método se o tamanho dos dados é grande ou ilimitado.
-
send_signal
(signal)¶ Envia o sinal signal para o processo filho.
Nota
No Windows,
SIGTERM
é um apelido paraterminate()
.CTRL_C_EVENT
eCTRL_BREAK_EVENT
podem ser enviados para processos iniciados com um parâmetro creationflags, o qual incluiCREATE_NEW_PROCESS_GROUP
.
-
terminate
()¶ Interrompe o processo filho.
Em sistemas POSIX este método envia
signal.SIGTERM
para o processo filho.No Windows a função
TerminateProcess()
da API Win32 é chamada para interromper o processo filho.
-
kill
()¶ Kill the child process.
Em sistemas POSIX este método envia
SIGKILL
para o processo filho.No Windows, este método é um atalho para
terminate()
.
-
stdin
¶ Fluxo de entrada padrão (
StreamWriter
) ouNone
se o processo foi criado comstdin=None
.
-
stdout
¶ Fluxo de saída padrão (
StreamReader
) ouNone
se o processo foi criado comstdout=None
.
-
stderr
¶ Erro de fluxo padrão (
StreamReader
) ouNone
se o processo foi criado comstderr=None
.
Aviso
Use o método
communicate()
ao invés deprocess.stdin.write()
,await process.stdout.read()
ouawait process.stderr.read
. Isso evita deadlocks devido a fluxos pausando a leitura ou escrita, e bloqueando o processo filho.-
pid
¶ Número de identificação do processo (PID).
Perceba que para processos criados pela função
create_subprocess_shell()
, este atributo é o PID do console gerado.
-
returncode
¶ Retorna o código do processo quando o mesmo terminar.
Um valor
None
indica que o processo ainda não terminou.Um valor negativo
-N
indica que o filho foi terminado pelo sinalN
(POSIX apenas).
Subprocesso e Threads¶
Laço de eventos padrão do asyncio suporta a execução de subprocessos a partir de diferentes threads por padrão.
No Windows, subprocessos são fornecidos pela classe ProactorEventLoop
apenas (por padrão), a classe SelectorEventLoop
não tem suporte a subprocesso.
Em sistemas UNIX, monitores de filhos são usados para aguardar o encerramento de subprocesso, veja Monitores de processos para mais informações.
Alterado na versão 3.8: UNIX mudou para usar ThreadedChildWatcher
para gerar subprocessos a partir de diferentes threads sem qualquer limitação.
Gerar um subprocesso com um monitor inativo para o filho atual, levanta RuntimeError
.
Perceba que implementações alternativas do laço de eventos podem ter limitações próprias; por favor, verifique a sua documentação.
Ver também
Exemplos¶
Um exemplo de uso da classe Process
para controlar um subprocesso e a classe StreamReader
para ler a partir da sua saída padrão.
O subprocesso é criado pela função 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}")
Veja também o mesmo exemplo escrito usando APIs de baixo nível.