Maison  >  Article  >  développement back-end  >  Quelle est la manière dont Python exécute une commande de manière asynchrone dans un sous-processus non bloquant

Quelle est la manière dont Python exécute une commande de manière asynchrone dans un sous-processus non bloquant

WBOY
WBOYavant
2023-06-02 18:51:241442parcourir

1. Qu'est-ce que asyncio.subprocess.Process

Nous pouvons exécuter des commandes depuis asyncio. Cette commande sera exécutée dans un processus enfant autorisé à utiliser des E/S non bloquantes pour les opérations de lecture et d'écriture.

Le module de sous-processus du module asyncio fournit une classe Process qui représente un sous-processus exécuté par asyncio. Dans un programme asyncio, il fournit un handle au processus enfant, permettant d'effectuer des opérations sur celui-ci, telles que l'attente et la fin.

L'API est très similaire à la classe multiprocessing.Process et probablement plus similaire à la classe subprocess.Popen. Plus précisément, il partage des méthodes telles que wait(), communicate() et send_signal() et des propriétés telles que stdin, stdout et stderr avec subprocess.Popen.

Maintenant que nous savons ce qu'est la classe asyncio.subprocess.Process, voyons comment l'utiliser dans notre programme asyncio.

Nous ne générerons pas directement les instances asyncio.subprocess.Process. En revanche, lors de l'exécution d'un sous-processus dans un programme asyncio, une instance d'une classe est automatiquement créée.

Il existe deux façons d'exécuter un programme externe en tant que sous-processus et d'obtenir une instance de processus :

  • asyncio.create_subprocess_exec() est utilisé pour exécuter la commande directement.

  • Utilisez la fonction asyncio.create_subprocess_shell() pour exécuter des commandes à l'aide d'un shell.

Regardons chaque exemple tour à tour.

2. Comment exécuter une commande directement

Une commande est un programme qui est exécuté sur la ligne de commande (terminal ou invite de commande). Il s'agit d'un autre programme qui s'exécute directement.

Un exemple courant sous Linux et macOS pourrait être :

  • ‘ls’ liste le contenu d'un répertoire

  • ‘cat’ rapporte le contenu d'un fichier

  • date du rapport "données"

  • ‘echo’ Signaler une chaîne

  • ‘sleep» Dormir quelques secondes

En utilisant la fonction create_subprocess_exec(), nous pouvons exécuter des commandes dans le programme asyncio.

La fonction asyncio.create_subprocess_exec() accepte une commande et l'exécute directement.

Ceci est utile car cela permet à la commande d'être exécutée dans le processus enfant et permet à la coroutine asyncio de la lire, d'écrire et d'attendre.

Contrairement à la fonction asyncio.create_subprocess_shell(), asyncio.create_subprocess_exec() n'utilise pas le shell pour exécuter des commandes.

Cela signifie que les fonctionnalités fournies par le shell, telles que les variables shell, les scripts et les caractères génériques, ne sont pas disponibles lors de l'exécution de commandes.

Cela signifie également que l'exécution de la commande peut être plus sûre car il n'y a aucune possibilité d'injection de shell.

Maintenant que nous savons ce que fait asyncio.create_subprocess_exec(), voyons comment l'utiliser.

2.1. Comment utiliser Asyncio create_subprocess_exec()

La fonction asyncio.create_subprocess_exec() exécutera la commande de chaîne donnée dans le sous-processus.

Il renvoie un objet asyncio.subprocess.Process représentant le sous-processus.

Puisque la fonction create_subprocess_exec() est une coroutine, nous devons l'attendre. Il revient après le démarrage du sous-processus, et non à la fin du sous-processus.

...
# execute a command in a subprocess
process = await asyncio.create_subprocess_exec('ls')

Lors de l'utilisation de la fonction create_subprocess_exec(), les arguments de la commande doivent être fournis comme arguments suivants.

...
# execute a command with arguments in a subprocess
process = await asyncio.create_subprocess_exec('ls', '-l')

Nous pouvons attendre la fin du processus enfant en attendant la méthode wait().

...
# wait for the subprocess to terminate
await process.wait()

Nous pouvons arrêter le processus enfant directement en appelant la méthode terminate() ou kill(), ce qui déclenchera un signal dans le processus enfant.

...
# terminate the subprocess
process.terminate()

Les entrées, sorties et erreurs standard seront gérées via stdin, stderr et stdout. Nous pouvons laisser le programme asyncio gérer l’entrée ou la sortie du processus enfant.

Cela peut être réalisé en spécifiant un flux d'entrée ou de sortie et en spécifiant une constante à rediriger, telle que asyncio.subprocess.PIPE.

Par exemple, nous pouvons rediriger la sortie de la commande vers le programme asyncio :

...
# start a subprocess and redirect output
process = await asyncio.create_subprocess_exec('ls', stdout=asyncio.subprocess.PIPE)

Ensuite, nous pouvons lire la sortie du programme via la méthode communicate() via l'instance asyncio.subprocess.Process.

Cette méthode est une coroutine et doit attendre. Il est utilisé pour envoyer et recevoir des données via des sous-processus.

...
# read data from the subprocess
line = process.communicate()

Nous pouvons également envoyer des données au processus enfant via la méthode communicate() en définissant le paramètre "input" en octets.

...
# 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')

Sous le capot, asyncio.subprocess.PIPE configure le sous-processus pour pointer vers un StreamReader ou StreamWriter pour envoyer des données vers ou depuis le sous-processus, et la méthode communicate() lira à partir du lecteur configuré ou écrirea des octets.

Nous pouvons interagir directement avec StreamReader ou StreamWriter via le sous-processus via les propriétés stdin, stdout et stderr.

...
# read a line from the subprocess output stream
line = await process.stdout.readline()

Examinons quelques exemples pratiques d'utilisation de la fonction create_subprocess_exec(), maintenant que nous savons comment l'utiliser.

2.2. Exemple d'Asyncio create_subprocess_exec()

Nous pouvons explorer comment exécuter des commandes dans un sous-processus d'asyncio. Dans cet exemple, nous exécuterons la commande "echo" pour signaler une chaîne.

La commande echo signalera la chaîne fournie directement sur la sortie standard. Un exemple complet est répertorié ci-dessous.

Veuillez noter que cet exemple suppose que vous avez accès à la commande "echo", je ne sais pas si cela fonctionnera sous 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>

3. 如何通过 Shell 运行命令

我们可以使用 shell 执行命令。称为命令行解释器 (CLI),shell 是用来操作命令行界面的用户界面。它将代表用户解释和执行命令。

它还提供诸如用于脚本、通配符、管道、shell 变量(例如 PATH)等的原始编程语言等功能。

例如,我们可以将一条命令的输出重定向为另一条命令的输入,比如将“/etc/services”文件的内容重定向到word count命令“wc”中,统计行数:

cat /etc/services | wc -l

基于 Unix 的操作系统中的 shell 示例包括:

Quelle est la manière dont Python exécute une commande de manière asynchrone dans un sous-processus non bloquant

shell 已经在运行,它被用来启动 Python 程序。您无需执行任何特殊操作即可获取或访问 shell。

我们可以通过 create_subprocess_shell() 函数从 asyncio 程序执行命令。

asyncio.create_subprocess_shell() 函数接受一个命令并使用当前用户 shell 执行它。

这很有用,因为它不仅允许执行命令,还允许使用 shell 的功能,例如重定向、通配符等。

该命令将在执行 asyncio 程序的进程的子进程中执行。重要的是,asyncio 程序能够与子进程异步交互,例如通过协程。

通过 shell 而不是直接执行命令时,可能会有安全考虑。

这是因为请求执行命令和正在执行的命令之间至少存在一层间接和解释,允许可能的恶意注入。

现在我们知道了 asyncio.create_subprocess_shell() 的作用,让我们看看如何使用它。

3.1. 如何使用 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(&#39;ls&#39;)

我们可以通过等待 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(&#39;ls&#39;, 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(&#39;ls&#39;, stdin=asyncio.subprocess.PIPE)
# send data to the subprocess
process.communicate(input=b&#39;Hello\n&#39;)

在后台,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() 函数,接下来让我们查看一些实际工作示例。

3.2. Asyncio 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(&#39;echo Hello World&#39;)
    # report the details of the subprocess
    print(f&#39;subprocess: {process}&#39;)
 
# 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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer