A subprocess is a process launched by another process to run an external program. In an asynchronous Python application, it lets existing command-line tools or programs written in other languages participate without reimplementation. section 13.0 section 13.1
Use asyncio subprocesses to control execution and communication:
- Prefer create_subprocess_exec for predictable argument-based execution; use create_subprocess_shell only when shell functionality is required. section 13.1
- Await Process.wait() to observe completion, and terminate a process after a timeout when it runs too long. section 13.1
- Pipe standard output or input through StreamReader and StreamWriter objects when the application must inspect or exchange data. section 13.1.1 section 13.2
- Consume piped output while the process runs; otherwise, a large output stream can fill buffers and deadlock the application. section 13.1.1 section 13.3
Reusing a Rust batch processor
A Python web API can launch an existing Rust command-line batch processor, read its results, and expose that functionality without rewriting the processor. For a one-shot exchange, communicate() can send input and wait for completion; a repeatedly interactive program requires concurrent input writing and output reading. section 13.1 section 13.2
Listing 13.1 Running a simple command in a subprocess
import asyncio
from asyncio.subprocess import Process
async def main():
process: Process = await asyncio.create_subprocess_exec('ls', '-l')
print(f'Process pid is: {process.pid}')
status_code = await process.wait()
print(f'Status code: {status_code}')
asyncio.run(main())
Runnable asyncio example that launches ls, reports the process identifier, waits for completion, and prints the status code. section 13.1
