Heim  >  Artikel  >  Backend-Entwicklung  >  Wie kann Python einen Befehl asynchron in einem nicht blockierenden Unterprozess ausführen?

Wie kann Python einen Befehl asynchron in einem nicht blockierenden Unterprozess ausführen?

WBOY
WBOYnach vorne
2023-06-02 18:51:241442Durchsuche

1. Was ist asyncio.subprocess.Process? Wir können Befehle von asyncio ausführen. Dieser Befehl wird in einem untergeordneten Prozess ausgeführt, der nicht blockierende E/A für Lese- und Schreibvorgänge verwenden darf.

Das Unterprozessmodul im Asyncio-Modul stellt eine Process-Klasse bereit, die einen von Asyncio ausgeführten Unterprozess darstellt. In einem Asyncio-Programm stellt es ein Handle für den untergeordneten Prozess bereit und ermöglicht so die Ausführung von Vorgängen wie Warten und Beenden.

Die API ist der Klasse multiprocessing.Process sehr ähnlich und wahrscheinlich eher der Klasse subprocess.Popen. Insbesondere teilt es Methoden wie wait(), communication() und send_signal() sowie Eigenschaften wie stdin, stdout und stderr mit subprocess.Popen.

Da wir nun wissen, was die Klasse asyncio.subprocess.Process ist, sehen wir uns an, wie wir sie in unserem Asyncio-Programm verwenden.

Wir werden keine asyncio.subprocess.Process-Instanzen direkt generieren. Im Gegensatz dazu wird beim Ausführen eines Unterprozesses in einem Asyncio-Programm automatisch eine Instanz einer Klasse erstellt.

Es gibt zwei Möglichkeiten, ein externes Programm als Unterprozess auszuführen und eine Prozessinstanz zu erhalten:

    asyncio.create_subprocess_exec() wird verwendet, um den Befehl direkt auszuführen.
  • Verwenden Sie die Funktion asyncio.create_subprocess_shell(), um Befehle mithilfe einer Shell auszuführen.
  • Schauen wir uns die einzelnen Beispiele der Reihe nach an.

2. So führen Sie einen Befehl direkt aus

Ein Befehl ist ein Programm, das auf der Befehlszeile (Terminal oder Eingabeaufforderung) ausgeführt wird. Dies ist ein weiteres Programm, das direkt ausgeführt wird.

Ein häufiges Beispiel unter Linux und macOS könnte sein:

    ‘ls’ den Inhalt eines Verzeichnisses auflisten
  • ‘cat’ den Inhalt einer Datei melden
  • „Daten“-Berichtsdatum
  • ‘echo’ Einen String melden
  • ‘sleep’ Ein paar Sekunden lang schlafen
  • Mit der Funktion create_subprocess_exec() können wir Befehle im Asyncio-Programm ausführen.

Die Funktion asyncio.create_subprocess_exec() akzeptiert einen Befehl und führt ihn direkt aus.

Dies ist nützlich, da es die Ausführung des Befehls im untergeordneten Prozess ermöglicht und es der Asyncio-Coroutine ermöglicht, ihn zu lesen, zu schreiben und darauf zu warten.

Im Gegensatz zur Funktion asyncio.create_subprocess_shell() verwendet asyncio.create_subprocess_exec() nicht die Shell, um Befehle auszuführen.

Das bedeutet, dass von der Shell bereitgestellte Funktionen wie Shell-Variablen, Skripte und Platzhalter beim Ausführen von Befehlen nicht verfügbar sind.

Dies bedeutet auch, dass die Ausführung des Befehls möglicherweise sicherer ist, da keine Möglichkeit zur Shell-Injektion besteht.

Da wir nun wissen, was asyncio.create_subprocess_exec() macht, schauen wir uns an, wie man es verwendet.

2.1. So verwenden Sie Asyncio create_subprocess_exec()

Die Funktion asyncio.create_subprocess_exec() führt den angegebenen String-Befehl im Unterprozess aus.

Es gibt ein asyncio.subprocess.Process-Objekt zurück, das den Unterprozess darstellt.

Da die Funktion create_subprocess_exec() eine Coroutine ist, müssen wir darauf warten. Es kehrt zurück, nachdem der Unterprozess gestartet wurde, nicht, wenn der Unterprozess abgeschlossen ist.

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

Bei Verwendung der Funktion create_subprocess_exec() müssen die Argumente für den Befehl als nachfolgende Argumente bereitgestellt werden.

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

Wir können warten, bis der untergeordnete Prozess abgeschlossen ist, indem wir auf die Methode wait() warten.

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

Wir können den untergeordneten Prozess direkt stoppen, indem wir die Methode „terminate()“ oder „kill()“ aufrufen, wodurch ein Signal im untergeordneten Prozess ausgelöst wird.

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

Standardeingaben, -ausgaben und -fehler werden über stdin, stderr und stdout verarbeitet. Wir können das Asyncio-Programm die Eingabe oder Ausgabe des untergeordneten Prozesses verarbeiten lassen.

Dies kann erreicht werden, indem ein Eingabe- oder Ausgabestream und eine umzuleitende Konstante angegeben werden, z. B. asyncio.subprocess.PIPE.

Zum Beispiel können wir die Ausgabe des Befehls an das Asyncio-Programm umleiten:

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

Dann können wir die Ausgabe des Programms über die Methode communi() über die Instanz asyncio.subprocess.Process lesen.

Diese Methode ist eine Coroutine und muss warten. Es wird zum Senden und Empfangen von Daten über Unterprozesse verwendet.

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

Wir können Daten auch über die Methode communi() an den untergeordneten Prozess senden, indem wir den Parameter „input“ in Bytes festlegen.

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

Unter der Haube konfiguriert asyncio.subprocess.PIPE den Unterprozess so, dass er auf einen StreamReader oder StreamWriter verweist, um Daten an oder von dem Unterprozess zu senden, und die Methode communi() liest aus dem konfigurierten Leser oder schreibt Bytes.

Wir können über den Unterprozess über die Eigenschaften stdin, stdout und stderr direkt mit StreamReader oder StreamWriter interagieren.

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

Schauen wir uns einige praktische Beispiele für die Verwendung der Funktion „create_subprocess_exec()“ an, nachdem wir nun verstanden haben, wie man sie verwendet.

2.2. Asyncio create_subprocess_exec() Beispiel

Wir können untersuchen, wie Befehle in einem Unterprozess von Asyncio ausgeführt werden. In diesem Beispiel führen wir den Befehl „echo“ aus, um eine Zeichenfolge zu melden.

Der Echo-Befehl meldet die bereitgestellte Zeichenfolge direkt in der Standardausgabe. Ein vollständiges Beispiel ist unten aufgeführt.

Bitte beachten Sie, dass in diesem Beispiel davon ausgegangen wird, dass Sie Zugriff auf den Befehl „echo“ haben. Ich bin mir nicht sicher, ob er unter Windows funktioniert.

# 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 示例包括:

Wie kann Python einen Befehl asynchron in einem nicht blockierenden Unterprozess ausführen?

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

Das obige ist der detaillierte Inhalt vonWie kann Python einen Befehl asynchron in einem nicht blockierenden Unterprozess ausführen?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen