生成子进程¶
Spawning subprocesses
Trio 提供了支持生成其他程序作为子进程、通过管道与它们通信、发送信号并等待它们退出的功能。
大多数情况下,这通过我们的高级接口 trio.run_process()
来完成。它允许您运行一个进程直到完成,同时可选地捕获输出,或者将其运行在后台任务中,并在进程运行时与之交互:
- await trio.run_process(command, *, stdin=b'', capture_stdout=False, capture_stderr=False, check=True, deliver_cancel=None, task_status=TASK_STATUS_IGNORED, **options)¶
Run
command
in a subprocess and wait for it to complete.This function can be called in two different ways.
One option is a direct call, like:
completed_process_info = await trio.run_process(...)
In this case, it returns a
subprocess.CompletedProcess
instance describing the results. Use this if you want to treat a process like a function call.The other option is to run it as a task using Nursery.start – the enhanced version of ~Nursery.start_soon that lets a task pass back a value during startup:
process = await nursery.start(trio.run_process, ...)
In this case, ~Nursery.start returns a Process object that you can use to interact with the process while it's running. Use this if you want to treat a process like a background task.
Either way, run_process makes sure that the process has exited before returning, handles cancellation, optionally checks for errors, and provides some convenient shorthands for dealing with the child's input/output.
Input: run_process supports all the same
stdin=
arguments as subprocess.Popen. In addition, if you simply want to pass in some fixed data, you can pass a plain bytes object, and run_process will take care of setting up a pipe, feeding in the data you gave, and then sending end-of-file. The default isb""
, which means that the child will receive an empty stdin. If you want the child to instead read from the parent's stdin, usestdin=None
.Output: By default, any output produced by the subprocess is passed through to the standard output and error streams of the parent Trio process.
When calling run_process directly, you can capture the subprocess's output by passing
capture_stdout=True
to capture the subprocess's standard output, and/orcapture_stderr=True
to capture its standard error. Captured data is collected up by Trio into an in-memory buffer, and then provided as thestdout
and/orstderr
attributes of the returnedCompletedProcess
object. The value for any stream that was not captured will beNone
.If you want to capture both stdout and stderr while keeping them separate, pass
capture_stdout=True, capture_stderr=True
.If you want to capture both stdout and stderr but mixed together in the order they were printed, use:
capture_stdout=True, stderr=subprocess.STDOUT
. This directs the child's stderr into its stdout, so the combined output will be available in the ~subprocess.CompletedProcess.stdout attribute.If you're using
await nursery.start(trio.run_process, ...)
and want to capture the subprocess's output for further processing, then usestdout=subprocess.PIPE
and then make sure to read the data out of the Process.stdout stream. If you want to capture stderr separately, usestderr=subprocess.PIPE
. If you want to capture both, but mixed together in the correct order, usestdout=subprocess.PIPE, stderr=subprocess.STDOUT
.Error checking: If the subprocess exits with a nonzero status code, indicating failure,
run_process()
raises asubprocess.CalledProcessError
exception rather than returning normally. The captured outputs are still available as thestdout
andstderr
attributes of that exception. To disable this behavior, so thatrun_process()
returns normally even if the subprocess exits abnormally, passcheck=False
.Note that this can make the
capture_stdout
andcapture_stderr
arguments useful even when starting run_process as a task: if you only care about the output if the process fails, then you can enable capturing and then read the output off of the ~subprocess.CalledProcessError.Cancellation: If cancelled, run_process sends a termination request to the subprocess, then waits for it to fully exit. The
deliver_cancel
argument lets you control how the process is terminated.备注
run_process is intentionally similar to the standard library subprocess.run, but some of the defaults are different. Specifically, we default to:
check=True
, because "errors should never pass silently / unless explicitly silenced".stdin=b""
, because it produces less-confusing results if a subprocess unexpectedly tries to read from stdin.
To get the subprocess.run semantics, use
check=False, stdin=None
.- 参数:
command (list or str) -- The command to run. Typically this is a sequence of strings such as
['ls', '-l', 'directory with spaces']
, where the first element names the executable to invoke and the other elements specify its arguments. Withshell=True
in the**options
, or on Windows,command
may alternatively be a string, which will be parsed following platform-dependent quoting rules.stdin (
bytes
, subprocess.PIPE, file descriptor, or None) --The bytes to provide to the subprocess on its standard input stream, or
None
if the subprocess's standard input should come from the same place as the parent Trio process's standard input. As is the case with thesubprocess
module, you can also pass a file descriptor or an object with afileno()
method, in which case the subprocess's standard input will come from that file.When starting run_process as a background task, you can also use
stdin=subprocess.PIPE
, in which case Process.stdin will be a ~trio.abc.SendStream that you can use to send data to the child.capture_stdout (bool) -- If true, capture the bytes that the subprocess writes to its standard output stream and return them in the ~subprocess.CompletedProcess.stdout attribute of the returned subprocess.CompletedProcess or subprocess.CalledProcessError.
capture_stderr (bool) -- If true, capture the bytes that the subprocess writes to its standard error stream and return them in the ~subprocess.CompletedProcess.stderr attribute of the returned ~subprocess.CompletedProcess or subprocess.CalledProcessError.
check (bool) -- If false, don't validate that the subprocess exits successfully. You should be sure to check the
returncode
attribute of the returned object if you passcheck=False
, so that errors don't pass silently.deliver_cancel (async function or None) --
If run_process is cancelled, then it needs to kill the child process. There are multiple ways to do this, so we let you customize it.
If you pass None (the default), then the behavior depends on the platform:
On Windows, Trio calls
TerminateProcess
, which should kill the process immediately.On Unix-likes, the default behavior is to send a
SIGTERM
, wait 5 seconds, and send aSIGKILL
.
Alternatively, you can customize this behavior by passing in an arbitrary async function, which will be called with the Process object as an argument. For example, the default Unix behavior could be implemented like this:
async def my_deliver_cancel(process): process.send_signal(signal.SIGTERM) await trio.sleep(5) process.send_signal(signal.SIGKILL)
When the process actually exits, the
deliver_cancel
function will automatically be cancelled – so if the process exits afterSIGTERM
, then we'll never reach theSIGKILL
.In any case, run_process will always wait for the child process to exit before raising Cancelled.
**options (object) --
run_process()
also accepts any general subprocess options and passes them on to theProcess
constructor. This includes thestdout
andstderr
options, which provide additional redirection possibilities such asstderr=subprocess.STDOUT
,stdout=subprocess.DEVNULL
, or file descriptors.
- 返回类型:
subprocess.CompletedProcess[bytes]
- 返回:
When called normally – a subprocess.CompletedProcess instance describing the return code and outputs.
When called via Nursery.start – a trio.Process instance.
- 抛出:
UnicodeError -- if
stdin
is specified as a Unicode string, rather than bytesValueError -- if multiple redirections are specified for the same stream, e.g., both
capture_stdout=True
andstdout=subprocess.DEVNULL
subprocess.CalledProcessError -- if
check=False
is not passed and the process exits with a nonzero exit statusOSError -- if an error is encountered starting or communicating with the process
ExceptionGroup -- if exceptions occur in
deliver_cancel
, or when exceptions occur when communicating with the subprocess. If strict_exception_groups is set to false in the global context, which is deprecated, then single exceptions will be collapsed.
备注
The child process runs in the same process group as the parent Trio process, so a Ctrl+C will be delivered simultaneously to both parent and child. If you don't want this behavior, consult your platform's documentation for starting child processes in a different process group.
- class trio._subprocess.HasFileno(Protocol)¶
基类:
Protocol
Represents any file-like object that has a file descriptor.
- class trio.Process(popen, stdin, stdout, stderr)¶
基类:
object
A child process. Like
subprocess.Popen
, but async.This class has no public constructor. The most common way to get a Process object is to combine Nursery.start with run_process:
process_object = await nursery.start(run_process, ...)
This way, run_process supervises the process and makes sure that it is cleaned up properly, while optionally checking the return value, feeding it input, and so on.
If you need more control – for example, because you want to spawn a child process that outlives your program – then another option is to use trio.lowlevel.open_process:
process_object = await trio.lowlevel.open_process(...)
- args¶
The
command
passed at construction time, specifying the process to execute and its arguments.
- stdin¶
A stream connected to the child's standard input stream: when you write bytes here, they become available for the child to read. Only available if the
Process
was constructed usingstdin=PIPE
; otherwise this will be None.- Type:
trio.abc.SendStream or None
- stdout¶
A stream connected to the child's standard output stream: when the child writes to standard output, the written bytes become available for you to read here. Only available if the
Process
was constructed usingstdout=PIPE
; otherwise this will be None.- Type:
trio.abc.ReceiveStream or None
- stderr¶
A stream connected to the child's standard error stream: when the child writes to standard error, the written bytes become available for you to read here. Only available if the
Process
was constructed usingstderr=PIPE
; otherwise this will be None.- Type:
trio.abc.ReceiveStream or None
- stdio¶
A stream that sends data to the child's standard input and receives from the child's standard output. Only available if both
stdin
andstdout
are available; otherwise this will be None.- Type:
trio.StapledStream or None
- returncode¶
The exit status of the process (an integer), or
None
if it's still running.By convention, a return code of zero indicates success. On UNIX, negative values indicate termination due to a signal, e.g., -11 if terminated by signal 11 (
SIGSEGV
). On Windows, a process that exits due to a call toProcess.terminate()
will have an exit status of 1.Unlike the standard library subprocess.Popen.returncode, you don't have to call poll or wait to update this attribute; it's automatically updated as needed, and will always give you the latest information.
- await wait()¶
Block until the process exits.
- 返回类型:
- 返回:
The exit status of the process; see
returncode
.
- poll()¶
Returns the exit status of the process (an integer), or
None
if it's still running.Note that on Trio (unlike the standard library subprocess.Popen),
process.poll()
andprocess.returncode
always give the same result. See returncode for more details. This method is only included to make it easier to port code from subprocess.
- kill()¶
Immediately terminate the process.
On UNIX, this is equivalent to
send_signal(signal.SIGKILL)
. On Windows, it callsTerminateProcess
. In both cases, the process cannot prevent itself from being killed, but the termination will be delivered asynchronously; usewait()
if you want to ensure the process is actually dead before proceeding.- 返回类型:
- terminate()¶
Terminate the process, politely if possible.
On UNIX, this is equivalent to
send_signal(signal.SIGTERM)
; by convention this requests graceful termination, but a misbehaving or buggy process might ignore it. On Windows,terminate()
forcibly terminates the process in the same manner askill()
.- 返回类型:
- send_signal(sig)¶
Send signal
sig
to the process.On UNIX,
sig
may be any signal defined in thesignal
module, such assignal.SIGINT
orsignal.SIGTERM
. On Windows, it may be anything accepted by the standard librarysubprocess.Popen.send_signal()
.- 返回类型:
备注
communicate()
不是Process
对象上的方法;对于简单的捕获,正常调用run_process()
,或者如果您有特殊需求,可以自己编写循环。communicate()
在标准库中有非常不寻常的取消行为(在某些平台上,它会生成一个后台线程,在超时过期后仍然继续从子进程读取),我们希望提供一个更少惊讶的接口。- kill()¶
Immediately terminate the process.
On UNIX, this is equivalent to
send_signal(signal.SIGKILL)
. On Windows, it callsTerminateProcess
. In both cases, the process cannot prevent itself from being killed, but the termination will be delivered asynchronously; usewait()
if you want to ensure the process is actually dead before proceeding.- 返回类型:
- poll()¶
Returns the exit status of the process (an integer), or
None
if it's still running.Note that on Trio (unlike the standard library subprocess.Popen),
process.poll()
andprocess.returncode
always give the same result. See returncode for more details. This method is only included to make it easier to port code from subprocess.
- property returncode: int | None¶
The exit status of the process (an integer), or
None
if it's still running.By convention, a return code of zero indicates success. On UNIX, negative values indicate termination due to a signal, e.g., -11 if terminated by signal 11 (
SIGSEGV
). On Windows, a process that exits due to a call toProcess.terminate()
will have an exit status of 1.Unlike the standard library subprocess.Popen.returncode, you don't have to call poll or wait to update this attribute; it's automatically updated as needed, and will always give you the latest information.
- send_signal(sig)¶
Send signal
sig
to the process.On UNIX,
sig
may be any signal defined in thesignal
module, such assignal.SIGINT
orsignal.SIGTERM
. On Windows, it may be anything accepted by the standard librarysubprocess.Popen.send_signal()
.- 返回类型:
- terminate()¶
Terminate the process, politely if possible.
On UNIX, this is equivalent to
send_signal(signal.SIGTERM)
; by convention this requests graceful termination, but a misbehaving or buggy process might ignore it. On Windows,terminate()
forcibly terminates the process in the same manner askill()
.- 返回类型:
- await wait()¶
Block until the process exits.
- 返回类型:
- 返回:
The exit status of the process; see
returncode
.
如果 trio.run_process()
太有限制,我们还提供了一个低级 API, trio.lowlevel.open_process()
。例如,如果您想生成一个将比父进程生命周期更长并且会成为孤儿的子进程,那么 run_process()
做不到这一点,但 open_process()
可以。
Trio provides support for spawning other programs as subprocesses, communicating with them via pipes, sending them signals, and waiting for them to exit.
Most of the time, this is done through our high-level interface,
trio.run_process()
. It lets you either run a process to completion
while optionally capturing the output, or else run it in a background
task and interact with it while it's running:
- await trio.run_process(command, *, stdin=b'', capture_stdout=False, capture_stderr=False, check=True, deliver_cancel=None, task_status=TASK_STATUS_IGNORED, **options)
Run
command
in a subprocess and wait for it to complete.This function can be called in two different ways.
One option is a direct call, like:
completed_process_info = await trio.run_process(...)
In this case, it returns a
subprocess.CompletedProcess
instance describing the results. Use this if you want to treat a process like a function call.The other option is to run it as a task using Nursery.start – the enhanced version of ~Nursery.start_soon that lets a task pass back a value during startup:
process = await nursery.start(trio.run_process, ...)
In this case, ~Nursery.start returns a Process object that you can use to interact with the process while it's running. Use this if you want to treat a process like a background task.
Either way, run_process makes sure that the process has exited before returning, handles cancellation, optionally checks for errors, and provides some convenient shorthands for dealing with the child's input/output.
Input: run_process supports all the same
stdin=
arguments as subprocess.Popen. In addition, if you simply want to pass in some fixed data, you can pass a plain bytes object, and run_process will take care of setting up a pipe, feeding in the data you gave, and then sending end-of-file. The default isb""
, which means that the child will receive an empty stdin. If you want the child to instead read from the parent's stdin, usestdin=None
.Output: By default, any output produced by the subprocess is passed through to the standard output and error streams of the parent Trio process.
When calling run_process directly, you can capture the subprocess's output by passing
capture_stdout=True
to capture the subprocess's standard output, and/orcapture_stderr=True
to capture its standard error. Captured data is collected up by Trio into an in-memory buffer, and then provided as thestdout
and/orstderr
attributes of the returnedCompletedProcess
object. The value for any stream that was not captured will beNone
.If you want to capture both stdout and stderr while keeping them separate, pass
capture_stdout=True, capture_stderr=True
.If you want to capture both stdout and stderr but mixed together in the order they were printed, use:
capture_stdout=True, stderr=subprocess.STDOUT
. This directs the child's stderr into its stdout, so the combined output will be available in the ~subprocess.CompletedProcess.stdout attribute.If you're using
await nursery.start(trio.run_process, ...)
and want to capture the subprocess's output for further processing, then usestdout=subprocess.PIPE
and then make sure to read the data out of the Process.stdout stream. If you want to capture stderr separately, usestderr=subprocess.PIPE
. If you want to capture both, but mixed together in the correct order, usestdout=subprocess.PIPE, stderr=subprocess.STDOUT
.Error checking: If the subprocess exits with a nonzero status code, indicating failure,
run_process()
raises asubprocess.CalledProcessError
exception rather than returning normally. The captured outputs are still available as thestdout
andstderr
attributes of that exception. To disable this behavior, so thatrun_process()
returns normally even if the subprocess exits abnormally, passcheck=False
.Note that this can make the
capture_stdout
andcapture_stderr
arguments useful even when starting run_process as a task: if you only care about the output if the process fails, then you can enable capturing and then read the output off of the ~subprocess.CalledProcessError.Cancellation: If cancelled, run_process sends a termination request to the subprocess, then waits for it to fully exit. The
deliver_cancel
argument lets you control how the process is terminated.备注
run_process is intentionally similar to the standard library subprocess.run, but some of the defaults are different. Specifically, we default to:
check=True
, because "errors should never pass silently / unless explicitly silenced".stdin=b""
, because it produces less-confusing results if a subprocess unexpectedly tries to read from stdin.
To get the subprocess.run semantics, use
check=False, stdin=None
.- 参数:
command (list or str) -- The command to run. Typically this is a sequence of strings such as
['ls', '-l', 'directory with spaces']
, where the first element names the executable to invoke and the other elements specify its arguments. Withshell=True
in the**options
, or on Windows,command
may alternatively be a string, which will be parsed following platform-dependent quoting rules.stdin (
bytes
, subprocess.PIPE, file descriptor, or None) --The bytes to provide to the subprocess on its standard input stream, or
None
if the subprocess's standard input should come from the same place as the parent Trio process's standard input. As is the case with thesubprocess
module, you can also pass a file descriptor or an object with afileno()
method, in which case the subprocess's standard input will come from that file.When starting run_process as a background task, you can also use
stdin=subprocess.PIPE
, in which case Process.stdin will be a ~trio.abc.SendStream that you can use to send data to the child.capture_stdout (bool) -- If true, capture the bytes that the subprocess writes to its standard output stream and return them in the ~subprocess.CompletedProcess.stdout attribute of the returned subprocess.CompletedProcess or subprocess.CalledProcessError.
capture_stderr (bool) -- If true, capture the bytes that the subprocess writes to its standard error stream and return them in the ~subprocess.CompletedProcess.stderr attribute of the returned ~subprocess.CompletedProcess or subprocess.CalledProcessError.
check (bool) -- If false, don't validate that the subprocess exits successfully. You should be sure to check the
returncode
attribute of the returned object if you passcheck=False
, so that errors don't pass silently.deliver_cancel (async function or None) --
If run_process is cancelled, then it needs to kill the child process. There are multiple ways to do this, so we let you customize it.
If you pass None (the default), then the behavior depends on the platform:
On Windows, Trio calls
TerminateProcess
, which should kill the process immediately.On Unix-likes, the default behavior is to send a
SIGTERM
, wait 5 seconds, and send aSIGKILL
.
Alternatively, you can customize this behavior by passing in an arbitrary async function, which will be called with the Process object as an argument. For example, the default Unix behavior could be implemented like this:
async def my_deliver_cancel(process): process.send_signal(signal.SIGTERM) await trio.sleep(5) process.send_signal(signal.SIGKILL)
When the process actually exits, the
deliver_cancel
function will automatically be cancelled – so if the process exits afterSIGTERM
, then we'll never reach theSIGKILL
.In any case, run_process will always wait for the child process to exit before raising Cancelled.
**options (
object
) --run_process()
also accepts any general subprocess options and passes them on to theProcess
constructor. This includes thestdout
andstderr
options, which provide additional redirection possibilities such asstderr=subprocess.STDOUT
,stdout=subprocess.DEVNULL
, or file descriptors.
- 返回类型:
- 返回:
When called normally – a subprocess.CompletedProcess instance describing the return code and outputs.
When called via Nursery.start – a trio.Process instance.
- 抛出:
UnicodeError -- if
stdin
is specified as a Unicode string, rather than bytesValueError -- if multiple redirections are specified for the same stream, e.g., both
capture_stdout=True
andstdout=subprocess.DEVNULL
subprocess.CalledProcessError -- if
check=False
is not passed and the process exits with a nonzero exit statusOSError -- if an error is encountered starting or communicating with the process
ExceptionGroup -- if exceptions occur in
deliver_cancel
, or when exceptions occur when communicating with the subprocess. If strict_exception_groups is set to false in the global context, which is deprecated, then single exceptions will be collapsed.
备注
The child process runs in the same process group as the parent Trio process, so a Ctrl+C will be delivered simultaneously to both parent and child. If you don't want this behavior, consult your platform's documentation for starting child processes in a different process group.
- class trio._subprocess.HasFileno(Protocol)
基类:
Protocol
Represents any file-like object that has a file descriptor.
- fileno()
- 返回类型:
- class trio.Process(popen, stdin, stdout, stderr)
基类:
object
A child process. Like
subprocess.Popen
, but async.This class has no public constructor. The most common way to get a Process object is to combine Nursery.start with run_process:
process_object = await nursery.start(run_process, ...)
This way, run_process supervises the process and makes sure that it is cleaned up properly, while optionally checking the return value, feeding it input, and so on.
If you need more control – for example, because you want to spawn a child process that outlives your program – then another option is to use trio.lowlevel.open_process:
process_object = await trio.lowlevel.open_process(...)
- args
The
command
passed at construction time, specifying the process to execute and its arguments.
- pid
The process ID of the child process managed by this object.
- Type:
- stdin
A stream connected to the child's standard input stream: when you write bytes here, they become available for the child to read. Only available if the
Process
was constructed usingstdin=PIPE
; otherwise this will be None.- Type:
trio.abc.SendStream or None
- stdout
A stream connected to the child's standard output stream: when the child writes to standard output, the written bytes become available for you to read here. Only available if the
Process
was constructed usingstdout=PIPE
; otherwise this will be None.- Type:
trio.abc.ReceiveStream or None
- stderr
A stream connected to the child's standard error stream: when the child writes to standard error, the written bytes become available for you to read here. Only available if the
Process
was constructed usingstderr=PIPE
; otherwise this will be None.- Type:
trio.abc.ReceiveStream or None
- stdio
A stream that sends data to the child's standard input and receives from the child's standard output. Only available if both
stdin
andstdout
are available; otherwise this will be None.- Type:
trio.StapledStream or None
- returncode
The exit status of the process (an integer), or
None
if it's still running.By convention, a return code of zero indicates success. On UNIX, negative values indicate termination due to a signal, e.g., -11 if terminated by signal 11 (
SIGSEGV
). On Windows, a process that exits due to a call toProcess.terminate()
will have an exit status of 1.Unlike the standard library subprocess.Popen.returncode, you don't have to call poll or wait to update this attribute; it's automatically updated as needed, and will always give you the latest information.
- await wait()
Block until the process exits.
- 返回类型:
- 返回:
The exit status of the process; see
returncode
.
- poll()
Returns the exit status of the process (an integer), or
None
if it's still running.Note that on Trio (unlike the standard library subprocess.Popen),
process.poll()
andprocess.returncode
always give the same result. See returncode for more details. This method is only included to make it easier to port code from subprocess.
- kill()
Immediately terminate the process.
On UNIX, this is equivalent to
send_signal(signal.SIGKILL)
. On Windows, it callsTerminateProcess
. In both cases, the process cannot prevent itself from being killed, but the termination will be delivered asynchronously; usewait()
if you want to ensure the process is actually dead before proceeding.- 返回类型:
- terminate()
Terminate the process, politely if possible.
On UNIX, this is equivalent to
send_signal(signal.SIGTERM)
; by convention this requests graceful termination, but a misbehaving or buggy process might ignore it. On Windows,terminate()
forcibly terminates the process in the same manner askill()
.- 返回类型:
- send_signal(sig)
Send signal
sig
to the process.On UNIX,
sig
may be any signal defined in thesignal
module, such assignal.SIGINT
orsignal.SIGTERM
. On Windows, it may be anything accepted by the standard librarysubprocess.Popen.send_signal()
.- 返回类型:
备注
communicate()
is not provided as a method onProcess
objects; callrun_process()
normally for simple capturing, or write the loop yourself if you have unusual needs.communicate()
has quite unusual cancellation behavior in the standard library (on some platforms it spawns a background thread which continues to read from the child process even after the timeout has expired) and we wanted to provide an interface with fewer surprises.- kill()
Immediately terminate the process.
On UNIX, this is equivalent to
send_signal(signal.SIGKILL)
. On Windows, it callsTerminateProcess
. In both cases, the process cannot prevent itself from being killed, but the termination will be delivered asynchronously; usewait()
if you want to ensure the process is actually dead before proceeding.- 返回类型:
- poll()
Returns the exit status of the process (an integer), or
None
if it's still running.Note that on Trio (unlike the standard library subprocess.Popen),
process.poll()
andprocess.returncode
always give the same result. See returncode for more details. This method is only included to make it easier to port code from subprocess.
- property returncode: int | None
The exit status of the process (an integer), or
None
if it's still running.By convention, a return code of zero indicates success. On UNIX, negative values indicate termination due to a signal, e.g., -11 if terminated by signal 11 (
SIGSEGV
). On Windows, a process that exits due to a call toProcess.terminate()
will have an exit status of 1.Unlike the standard library subprocess.Popen.returncode, you don't have to call poll or wait to update this attribute; it's automatically updated as needed, and will always give you the latest information.
- send_signal(sig)
Send signal
sig
to the process.On UNIX,
sig
may be any signal defined in thesignal
module, such assignal.SIGINT
orsignal.SIGTERM
. On Windows, it may be anything accepted by the standard librarysubprocess.Popen.send_signal()
.- 返回类型:
- terminate()
Terminate the process, politely if possible.
On UNIX, this is equivalent to
send_signal(signal.SIGTERM)
; by convention this requests graceful termination, but a misbehaving or buggy process might ignore it. On Windows,terminate()
forcibly terminates the process in the same manner askill()
.- 返回类型:
- await wait()
Block until the process exits.
- 返回类型:
- 返回:
The exit status of the process; see
returncode
.
If trio.run_process is too limiting, we also offer a low-level API, trio.lowlevel.open_process. For example, if you want to spawn a child process that will outlive the parent process and be orphaned, then ~trio.run_process can't do that, but ~trio.lowlevel.open_process can.
启动子进程的选项¶
Options for starting subprocesses
Trio 的所有子进程 API 都接受标准 subprocess
模块使用的众多关键字参数,用于控制进程启动的环境以及与之通信的机制。这些参数可以在以下文档中看到 **options
时传递。请参见 subprocess
文档中的 完整列表 或者 常用参数 。(您可能需要 import subprocess
才能访问像 PIPE
或 DEVNULL
这样的常量。)
目前,Trio 始终使用无缓冲的字节流与进程通信,因此不支持 encoding
、 errors
、universal_newlines
(别名 text
)和 bufsize
选项。
All of Trio's subprocess APIs accept the numerous keyword arguments used
by the standard subprocess
module to control the environment in
which a process starts and the mechanisms used for communicating with
it. These may be passed wherever you see **options
in the
documentation below. See the full list
or just the frequently used ones
in the subprocess
documentation. (You may need to import
subprocess
in order to access constants such as PIPE
or
DEVNULL
.)
Currently, Trio always uses unbuffered byte streams for communicating
with a process, so it does not support the encoding
, errors
,
universal_newlines
(alias text
), and bufsize
options.
引用:比您想知道的更多¶
Quoting: more than you wanted to know
Trio 的子进程 API 通常需要将要运行的命令及其参数作为字符串序列传递,其中序列的第一个元素指定要运行的命令,剩余的元素指定命令的参数,每个参数占一个元素。采用这种形式是因为它可以避免潜在的引号陷阱;例如,你可以运行 ["cp", "-f", source_file, dest_file]
,而无需担心 source_file
或 dest_file
是否包含空格。
如果你只在 UNIX 上运行不使用 shell=True
的子进程,那么指定命令时只需知道这些。如果你使用 shell=True
或在 Windows 上运行,可能需要阅读本节的其余部分,以便了解潜在的陷阱。
在 UNIX 上使用 shell=True
时,必须将命令指定为一个单一字符串,这个字符串将被传递给 shell,类似于你在交互式提示符下输入的方式。这个选项的优点是它允许你使用 shell 功能,比如管道和重定向,而不需要编写处理它们的代码。例如,你可以写 Process("ls | grep some_string", shell=True)
。缺点是你必须考虑到 shell 的引用规则,通常需要通过 shlex.quote()
来包装可能包含空格、引号或其他 shell 元字符的任何参数。如果你不这样做,那么看似安全的 f"ls | grep {some_string}"
在调用时,若 some_string = "foo; rm -rf /"
,可能会导致灾难。
在 Windows 上,进程生成的基本 API(CreateProcess()
系统调用)接受一个字符串而不是列表,实际上是子进程决定如何将这个字符串拆分为单独的参数。由于 C 语言规定 main()
应该接受一个参数列表,大多数 你遇到的程序将遵循 Microsoft C/C++ 运行时使用的规则。subprocess.Popen
,因此 Trio 也使用这些规则将参数序列转换为字符串,这些规则在 subprocess
模块中有 文档记录。没有文档化的 Python 标准库函数可以直接执行该转换,因此即使在 Windows 上,你几乎总是需要传递参数序列而不是字符串。但如果你启动的程序不能按标准方式将命令行拆分回单独的参数,那么你可能需要传递一个字符串来解决这个问题。(或者你可能只是运气不好:据我所知,Windows 批处理文件没有办法传递包含双引号的参数。)
在 Windows 上使用 shell=True
时,情况变得更加混乱。现在,有两个独立的引用规则应用:一个由 Windows 命令 shell CMD.EXE
使用,另一个由被启动的进程使用,而且它们是 不同的。(而且没有 shlex.quote()
来帮助你:它使用 UNIX 风格的引用规则,即使在 Windows 上也是如此。)大多数由 shell 解释的特殊字符 &<>()^|
如果 shell 认为它们在双引号内,则不被视为特殊字符,但 %FOO%
环境变量替换仍然有效,而且 shell 没有提供在双引号字符串内写入双引号的办法。双引号外部,任何字符(包括双引号)都可以使用前导 ^
来转义。但由于管道通过在子 shell 中运行每个命令来处理,因此可能需要多层转义:
echo ^^^&x | find "x" | find "x" # prints: &x
如果你将管道与 ()
分组结合使用,可能需要更多层的转义:
(echo ^^^^^^^&x | find "x") | find "x" # prints: &x
由于进程创建接受一个字符串参数,CMD.EXE
的引用规则不会影响单词拆分,并且在 CMD.EXE
扩展过程中不会删除双引号。双引号很麻烦,因为 CMD.EXE
处理它们的方式与 MSVC 运行时规则不同;例如:
prog.exe "foo \"bar\" baz"
程序会看到一个参数 foo "bar" baz
,但 CMD.EXE
认为 bar\
没有被引用,而 foo \
和 baz
被认为是引用的。所有这些使得在 Windows 上可靠地插入任何内容到 shell=True
命令行中变得非常困难,Trio 退回到 subprocess
的行为:如果你传递一个包含 shell=True
的序列,它会像 shell=False
一样进行引用,并且最好不要包含你未计划使用的任何 shell 元字符。
进一步阅读:
The command to run and its arguments usually must be passed to Trio's
subprocess APIs as a sequence of strings, where the first element in
the sequence specifies the command to run and the remaining elements
specify its arguments, one argument per element. This form is used
because it avoids potential quoting pitfalls; for example, you can run
["cp", "-f", source_file, dest_file]
without worrying about
whether source_file
or dest_file
contains spaces.
If you only run subprocesses without shell=True
and on UNIX,
that's all you need to know about specifying the command. If you use
shell=True
or run on Windows, you probably should read the
rest of this section to be aware of potential pitfalls.
With shell=True
on UNIX, you must specify the command as a single
string, which will be passed to the shell as if you'd entered it at an
interactive prompt. The advantage of this option is that it lets you
use shell features like pipes and redirection without writing code to
handle them. For example, you can write Process("ls | grep
some_string", shell=True)
. The disadvantage is that you must
account for the shell's quoting rules, generally by wrapping in
shlex.quote()
any argument that might contain spaces, quotes, or
other shell metacharacters. If you don't do that, your safe-looking
f"ls | grep {some_string}"
might end in disaster when invoked with
some_string = "foo; rm -rf /"
.
On Windows, the fundamental API for process spawning (the
CreateProcess()
system call) takes a string, not a list, and it's
actually up to the child process to decide how it wants to split that
string into individual arguments. Since the C language specifies that
main()
should take a list of arguments, most programs you
encounter will follow the rules used by the Microsoft C/C++ runtime.
subprocess.Popen
, and thus also Trio, uses these rules
when it converts an argument sequence to a string, and they
are documented
alongside the subprocess
module. There is no documented
Python standard library function that can directly perform that
conversion, so even on Windows, you almost always want to pass an
argument sequence rather than a string. But if the program you're
spawning doesn't split its command line back into individual arguments
in the standard way, you might need to pass a string to work around this.
(Or you might just be out of luck: as far as I can tell, there's simply
no way to pass an argument containing a double-quote to a Windows
batch file.)
On Windows with shell=True
, things get even more chaotic. Now
there are two separate sets of quoting rules applied, one by the
Windows command shell CMD.EXE
and one by the process being
spawned, and they're different. (And there's no shlex.quote()
to save you: it uses UNIX-style quoting rules, even on Windows.) Most
special characters interpreted by the shell &<>()^|
are not
treated as special if the shell thinks they're inside double quotes,
but %FOO%
environment variable substitutions still are, and the
shell doesn't provide any way to write a double quote inside a
double-quoted string. Outside double quotes, any character (including
a double quote) can be escaped using a leading ^
. But since a
pipeline is processed by running each command in the pipeline in a
subshell, multiple layers of escaping can be needed:
echo ^^^&x | find "x" | find "x" # prints: &x
And if you combine pipelines with () grouping, you can need even more levels of escaping:
(echo ^^^^^^^&x | find "x") | find "x" # prints: &x
Since process creation takes a single arguments string, CMD.EXE
's
quoting does not influence word splitting, and double quotes are not
removed during CMD.EXE's expansion pass. Double quotes are troublesome
because CMD.EXE handles them differently from the MSVC runtime rules; in:
prog.exe "foo \"bar\" baz"
the program will see one argument foo "bar" baz
but CMD.EXE thinks
bar\
is not quoted while foo \
and baz
are. All of this
makes it a formidable task to reliably interpolate anything into a
shell=True
command line on Windows, and Trio falls back on the
subprocess
behavior: If you pass a sequence with
shell=True
, it's quoted in the same way as a sequence with
shell=False
, and had better not contain any shell metacharacters
you weren't planning on.
Further reading: