We can execute commands from asyncio. This command will be executed in a child process that is allowed to use non-blocking I/O for read and write operations.
The subprocess module in the asyncio module provides the Process class that represents the subprocess run by asyncio. In an asyncio program, it provides a handle to the child process, making it possible to perform operations on it, such as waiting and terminating.
The API is very similar to the multiprocessing.Process class and probably more similar to the subprocess.Popen class. Specifically, it shares methods such as wait(), communicate(), and send_signal() and properties such as stdin, stdout, and stderr with subprocess.Popen.
Now that we know what the asyncio.subprocess.Process class is, let’s see how to use it in our asyncio program.
We will not generate asyncio.subprocess.Process instances directly. In contrast, when running a subprocess in an asyncio program, an instance of a class is automatically created.
There are two ways to execute an external program as a subprocess and obtain a Process instance, they are:
asyncio.create_subprocess_exec() is used to run the command directly.
Use the asyncio.create_subprocess_shell() function to run commands by using a shell.
Let’s look at each example in turn.
Commands are programs executed on the command line (terminal or command prompt). This is another program that runs directly.
A common example on Linux and macOS might be:
‘ls’ Listing the contents of a directory
&lsquo ;cat’Report file content
"data" report date
‘echo’Report a string
‘sleep’ Sleep for a few seconds
By using the create_subprocess_exec() function, we can execute commands in the asyncio program.
asyncio.create_subprocess_exec() function accepts a command and executes it directly.
This is useful because it allows the command to be executed in the child process and allows the asyncio coroutine to read, write and wait on it.
Unlike the asyncio.create_subprocess_shell() function, asyncio.create_subprocess_exec() does not use the shell to execute commands.
This means that features provided by the shell, such as shell variables, scripts, and wildcards, are not available when executing commands.
This also means that executing the command may be safer as there is no opportunity for shell injection.
Now that we know what asyncio.create_subprocess_exec() does, let’s see how to use it.
The asyncio.create_subprocess_exec() function will execute the given string command in the subprocess.
It returns an asyncio.subprocess.Process object representing the subprocess.
Since the create_subprocess_exec() function is a coroutine, we need to wait for it. It returns after the subprocess is started, not when the subprocess completes.
... # execute a command in a subprocess process = await asyncio.create_subprocess_exec('ls')
When using the create_subprocess_exec() function, the arguments to the command must be provided as subsequent arguments.
... # execute a command with arguments in a subprocess process = await asyncio.create_subprocess_exec('ls', '-l')
We can wait for the child process to complete by waiting for the wait() method.
... # wait for the subprocess to terminate await process.wait()
We can stop the child process directly by calling the terminate() or kill() method, which will raise a signal in the child process.
... # terminate the subprocess process.terminate()
Standard input, output and errors will be handled through stdin, stderr and stdout. We can let the asyncio program handle the input or output of the child process.
This can be achieved by specifying an input or output stream and specifying a constant to redirect, such as asyncio.subprocess.PIPE.
For example, we can redirect the output of the command to the asyncio program:
... # start a subprocess and redirect output process = await asyncio.create_subprocess_exec('ls', stdout=asyncio.subprocess.PIPE)
Then we can read the output of the program through the communicate() method through the asyncio.subprocess.Process instance.
This method is a coroutine and must wait. It is used to send and receive data through subprocesses.
... # read data from the subprocess line = process.communicate()
We can also send data to the child process through the communicate() method by setting the "input" parameter in bytes.
... # start a subprocess and redirect input process = await asyncio.create_subprocess_exec('ls', stdin=asyncio.subprocess.PIPE) # send data to the subprocess process.communicate(input=b'Hello\n')
In the background, asyncio.subprocess.PIPE configures the subprocess to point to a StreamReader or StreamWriter for sending data to or from the subprocess, and the communicate() method will read from the configured The processor reads or writes bytes.
We can interact directly with StreamReader or StreamWriter through the subprocess through the stdin, stdout and stderr properties.
... # read a line from the subprocess output stream line = await process.stdout.readline()
Let's look at some practical examples of using the create_subprocess_exec() function, now that we have a grasp on how to use it.
We can explore how to run commands in a subprocess of asyncio. In this example, we will execute the "echo" command to report a string.
The echo command will report the supplied string directly on standard output. A complete example is listed below.
Please note that this example assumes you have access to the "echo" command, I'm not sure if it will work on Windows.
# SuperFastPython.com # example of executing a command as a subprocess with asyncio import asyncio # main coroutine async def main(): # start executing a command in a subprocess process = await asyncio.create_subprocess_exec('echo', 'Hello World') # report the details of the subprocess print(f'subprocess: {process}') # entry point asyncio.run(main())
运行示例首先创建 main() 协程并将其作为 asyncio 程序的入口点执行。
main() 协程运行并调用 create_subprocess_exec() 函数来执行命令。
main() 协程在创建子进程时挂起。返回一个 Process 实例。
main() 协程恢复并报告子进程的详细信息。 main() 进程终止,asyncio 程序终止。
echo 命令的输出在命令行上报告。这突出了我们如何从 asyncio 程序执行命令。
Hello World subprocess: <Process 50249>
我们可以使用 shell 执行命令。称为命令行解释器 (CLI),shell 是用来操作命令行界面的用户界面。它将代表用户解释和执行命令。
它还提供诸如用于脚本、通配符、管道、shell 变量(例如 PATH)等的原始编程语言等功能。
例如,我们可以将一条命令的输出重定向为另一条命令的输入,比如将“/etc/services”文件的内容重定向到word count命令“wc”中,统计行数:
cat /etc/services | wc -l
基于 Unix 的操作系统中的 shell 示例包括:
shell 已经在运行,它被用来启动 Python 程序。您无需执行任何特殊操作即可获取或访问 shell。
我们可以通过 create_subprocess_shell() 函数从 asyncio 程序执行命令。
asyncio.create_subprocess_shell() 函数接受一个命令并使用当前用户 shell 执行它。
这很有用,因为它不仅允许执行命令,还允许使用 shell 的功能,例如重定向、通配符等。
该命令将在执行 asyncio 程序的进程的子进程中执行。重要的是,asyncio 程序能够与子进程异步交互,例如通过协程。
通过 shell 而不是直接执行命令时,可能会有安全考虑。
这是因为请求执行命令和正在执行的命令之间至少存在一层间接和解释,允许可能的恶意注入。
现在我们知道了 asyncio.create_subprocess_shell() 的作用,让我们看看如何使用它。
asyncio.create_subprocess_shell() 函数将通过当前 shell 执行给定的字符串命令。
它返回一个表示进程的 asyncio.subprocess.Process 对象。
它和上一节中介绍的 create_subprocess_shell() 函数非常类似。不过,我们将回顾如何使用该函数以及如何通过 Process 实例与流程交互(以防您直接跳到本节)。
我们需要等待create_subprocess_shell()函数完成,因为它是一个协程。它会在子流程启动后返回,而不是在子流程完成时返回。
... # start a subprocess process = await asyncio.create_subprocess_shell('ls')
我们可以通过等待 wait() 方法来等待子进程完成。
... # wait for the subprocess to terminate await process.wait()
我们可以通过调用 terminate() 或 kill() 方法直接停止子进程,这将在子进程中引发一个信号。
命令的输入和输出将由 shell 处理,例如标准输入、标准错误和标准输出。
我们可以让 asyncio 程序处理子进程的输入或输出。
这可以通过指定输入或输出流并指定要重定向的常量来实现,例如 asyncio.subprocess.PIPE。
例如,我们可以将命令的输出重定向到 asyncio 程序:
... # start a subprocess and redirect output process = await asyncio.create_subprocess_shell('ls', stdout=asyncio.subprocess.PIPE)
然后我们可以通过 asyncio.subprocess.Process 实例通过 communicate() 方法读取程序的输出。
此方法是协程,必须等待。它用于通过子流程发送和接收数据。
... # read data from the subprocess line = process.communicate()
我们还可以通过以字节为单位设置“input”参数,通过 communicate() 方法将数据发送到子进程。
... # start a subprocess and redirect input process = await asyncio.create_subprocess_shell('ls', stdin=asyncio.subprocess.PIPE) # send data to the subprocess process.communicate(input=b'Hello\n')
在后台,asyncio.subprocess.PIPE 将子进程配置为指向 StreamReader 或 StreamWriter,用于向子进程发送数据或从子进程发送数据,并且 communicate() 方法将从配置的读取器读取或写入字节。
我们可以通过子进程通过 stdin、stdout 和 stderr 属性直接与 StreamReader 或 StreamWriter 交互。
... # read a line from the subprocess output stream line = await process.stdout.readline()
现在我们已经掌握了如何使用 create_subprocess_shell() 函数,接下来让我们查看一些实际工作示例。
我们可以尝试用 shell 在 asyncio 的子进程中执行指令。在这个例子中,我们将执行“echo”命令来报告一个字符串。
echo 命令将直接在标准输出上报告提供的字符串。下面列出了完整的示例。
请注意,此示例假设您可以访问“echo”命令,我不确定它是否适用于 Windows。
# SuperFastPython.com # example of executing a shell command as a subprocess with asyncio import asyncio # main coroutine async def main(): # start executing a shell command in a subprocess process = await asyncio.create_subprocess_shell('echo Hello World') # report the details of the subprocess print(f'subprocess: {process}') # entry point asyncio.run(main())
首先创建 main() 协程并将其作为入口点运行的是 asyncio 程序的示例。在 main() 协程中,通过调用 create_subprocess_shell() 函数来执行命令。
main() 协程在运行时调用 create_subprocess_shell() 函数来执行命令。main() 协程恢复并报告子进程的详细信息。 main() 进程终止,asyncio 程序终止。
echo 命令的输出在命令行上报告。这个例子清晰地展示了我们如何利用 shell 从 asyncio 程序中运行命令。
subprocess: <Process 43916> Hello World
The above is the detailed content of What is Python's way to run a command asynchronously in a non-blocking subprocess. For more information, please follow other related articles on the PHP Chinese website!