Quy trình con¶
Source code: Lib/asyncio/subprocess.py, Lib/asyncio/base_subprocess.py
Phần này mô tả các API async/await asyncio cấp cao để tạo và quản lý các quy trình con.
Đây là một ví dụ về cách asyncio có thể chạy lệnh shell và nhận được kết quả của nó
nhập asyncio
chạy không đồng bộ (cmd):
proc = đang chờ asyncio.create_subprocess_shell(
cmd,
thiết bị xuất chuẩn = asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
thiết bị xuất chuẩn, stderr = đang chờ proc.communicate()
print(f'[{cmd!r} đã thoát với {proc.returncode}]')
nếu thiết bị xuất chuẩn:
print(f'[stdout]\n{stdout.decode()}')
nếu lỗi chuẩn:
print(f'[stderr]\n{stderr.decode()}')
asyncio.run(run('ls /zzz'))
sẽ in:
['ls /zzz' đã thoát với 1]
[stderr]
ls: /zzz: Không có tập tin hoặc thư mục như vậy
Bởi vì tất cả các hàm của quy trình con asyncio đều không đồng bộ và asyncio cung cấp nhiều công cụ để làm việc với các hàm đó nên rất dễ thực thi và giám sát nhiều quy trình con song song. Thực sự là không cần thiết khi sửa đổi ví dụ trên để chạy nhiều lệnh cùng lúc
async def main():
đang chờ asyncio.gather(
chạy('ls /zzz'),
run('ngủ 1; echo "xin chào"'))
asyncio.run(chính())
Xem thêm phần phụ Examples.
Tạo quy trình con¶
- async asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
Tạo một quy trình con.
Đối số limit đặt giới hạn bộ đệm cho các trình bao bọc
StreamReaderchostdoutvàstderr(nếusubprocess.PIPEđược chuyển cho các đối số stdout và stderr).Trả về một phiên bản
Process.Xem tài liệu của
loop.subprocess_exec()để biết các thông số khác.Nếu đối tượng tiến trình bị thu gom rác trong khi tiến trình vẫn đang chạy thì tiến trình con sẽ bị hủy.
Thay đổi trong phiên bản 3.10: Đã xóa tham số loop.
- async asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
Chạy lệnh shell cmd.
Đối số limit đặt giới hạn bộ đệm cho các trình bao bọc
StreamReaderchostdoutvàstderr(nếusubprocess.PIPEđược chuyển cho các đối số stdout và stderr).Trả về một phiên bản
Process.Xem tài liệu của
loop.subprocess_shell()để biết các thông số khác.Nếu đối tượng tiến trình bị thu gom rác trong khi tiến trình vẫn đang chạy thì tiến trình con sẽ bị hủy.
Quan trọng
Trách nhiệm của ứng dụng là đảm bảo rằng tất cả khoảng trắng và ký tự đặc biệt đều được trích dẫn một cách thích hợp để tránh các lỗ hổng shell injection. Hàm
shlex.quote()có thể được sử dụng để thoát khỏi khoảng trắng và các ký tự shell đặc biệt trong chuỗi sẽ được sử dụng để xây dựng các lệnh shell một cách chính xác.Thay đổi trong phiên bản 3.10: Đã xóa tham số loop.
Ghi chú
Các quy trình con có sẵn cho Windows nếu sử dụng ProactorEventLoop. Xem Subprocess Support on Windows để biết chi tiết.
Xem thêm
asyncio cũng có các API low-level sau để hoạt động với các quy trình con: loop.subprocess_exec(), loop.subprocess_shell(), loop.connect_read_pipe(), loop.connect_write_pipe(), cũng như Subprocess Transports và Subprocess Protocols.
Hằng số¶
- asyncio.subprocess.PIPE¶
Có thể được chuyển đến các tham số stdin, stdout hoặc stderr.
Nếu PIPE được truyền cho đối số stdin, thuộc tính
Process.stdinsẽ trỏ đến một phiên bảnStreamWriter.Nếu PIPE được chuyển tới các đối số stdout hoặc stderr, thuộc tính
Process.stdoutvàProcess.stderrsẽ trỏ đến các phiên bảnStreamReader.
- asyncio.subprocess.STDOUT¶
Giá trị đặc biệt có thể được sử dụng làm đối số stderr và cho biết rằng lỗi tiêu chuẩn sẽ được chuyển hướng sang đầu ra tiêu chuẩn.
- asyncio.subprocess.DEVNULL¶
Giá trị đặc biệt có thể được sử dụng làm đối số stdin, stdout hoặc stderr để xử lý các hàm tạo. Nó chỉ ra rằng tệp đặc biệt
os.devnullsẽ được sử dụng cho luồng quy trình con tương ứng.
Tương tác với các quy trình con¶
Cả hai hàm create_subprocess_exec() và create_subprocess_shell() đều trả về các thể hiện của lớp Process. Process là một trình bao bọc cấp cao cho phép giao tiếp với các quy trình con và theo dõi quá trình hoàn thành của chúng.
- class asyncio.subprocess.Process¶
Một đối tượng bao bọc các tiến trình hệ điều hành được tạo bởi các hàm
create_subprocess_exec()vàcreate_subprocess_shell().Lớp này được thiết kế để có API tương tự như lớp
subprocess.Popen, nhưng có một số khác biệt đáng chú ý:không giống như Popen, các phiên bản Process không có phương thức tương đương với phương thức
poll();phương thức
communicate()vàwait()không có tham số timeout: sử dụng hàmwait_for();phương thức
Process.wait()không đồng bộ, trong khi phương thứcsubprocess.Popen.wait()được triển khai như một vòng lặp bận rộn chặn;tham số universal_newlines không được hỗ trợ.
Lớp này là not thread safe.
Xem thêm phần Subprocess and Threads.
- async wait()¶
Đợi quá trình con kết thúc.
Đặt và trả về thuộc tính
returncode.Ghi chú
Phương pháp này có thể bế tắc khi sử dụng
stdout=PIPEhoặcstderr=PIPEvà tiến trình con tạo ra nhiều đầu ra đến mức chặn việc chờ bộ đệm ống hệ điều hành chấp nhận nhiều dữ liệu hơn. Sử dụng phương phápcommunicate()khi sử dụng ống để tránh tình trạng này.
- async communicate(input=None)¶
Tương tác với quá trình:
gửi dữ liệu tới stdin (nếu input không phải là
None);đóng stdin;
đọc dữ liệu từ stdout và stderr, cho đến khi đạt được EOF;
chờ quá trình kết thúc.
Đối số input tùy chọn là dữ liệu (đối tượng
bytes) sẽ được gửi đến tiến trình con.Trả về một bộ
(stdout_data, stderr_data).Nếu ngoại lệ
BrokenPipeErrorhoặcConnectionResetErrorđược nêu ra khi ghi input vào stdin thì ngoại lệ đó sẽ bị bỏ qua. Tình trạng này xảy ra khi quá trình thoát ra trước khi tất cả dữ liệu được ghi vào stdin.Nếu muốn gửi dữ liệu đến tiến trình' stdin, thì tiến trình đó cần được tạo bằng
stdin=PIPE. Tương tự, để nhận được bất kỳ thứ gì khác ngoàiNonetrong bộ kết quả, quy trình phải được tạo với các đối sốstdout=PIPEvà/hoặcstderr=PIPE.Lưu ý rằng dữ liệu đọc được lưu vào bộ đệm trong bộ nhớ, vì vậy không sử dụng phương pháp này nếu kích thước dữ liệu lớn hoặc không giới hạn.
Thay đổi trong phiên bản 3.12: stdin bị đóng khi
input=Nonecũng vậy.
- send_signal(signal)¶
Gửi tín hiệu signal đến tiến trình con.
Ghi chú
Trên Windows,
SIGTERMlà bí danh củaterminate().CTRL_C_EVENTvàCTRL_BREAK_EVENTcó thể được gửi đến các tiến trình được bắt đầu bằng tham số creationflags bao gồmCREATE_NEW_PROCESS_GROUP.
- terminate()¶
Dừng quá trình con.
Trên hệ thống POSIX, phương thức này gửi
SIGTERMđến tiến trình con.Trên Windows, hàm API Win32
TerminateProcess()được gọi để dừng tiến trình con.
- kill()¶
Giết tiến trình con.
Trên hệ thống POSIX, phương thức này gửi
SIGKILLđến tiến trình con.Trên Windows phương pháp này là bí danh cho
terminate().
- stdin¶
Luồng đầu vào tiêu chuẩn (
StreamWriter) hoặcNonenếu quy trình được tạo bằngstdin=None.
- stdout¶
Luồng đầu ra tiêu chuẩn (
StreamReader) hoặcNonenếu quy trình được tạo bằngstdout=None.
- stderr¶
Luồng lỗi tiêu chuẩn (
StreamReader) hoặcNonenếu quy trình được tạo bằngstderr=None.
Cảnh báo
Sử dụng phương pháp
communicate()thay vìprocess.stdin.write(),await process.stdout.read()hoặcawait process.stderr.read(). Điều này tránh được tình trạng bế tắc do các luồng tạm dừng đọc hoặc ghi và chặn tiến trình con.- pid¶
Số nhận dạng quy trình (PID).
Lưu ý rằng đối với các quy trình được tạo bởi hàm
create_subprocess_shell(), thuộc tính này là PID của shell được sinh ra.
- returncode¶
Trả lại mã của quá trình khi nó thoát.
Giá trị
Nonecho biết quá trình này chưa kết thúc.Đối với các tiến trình được tạo bằng
create_subprocess_exec(), giá trị âm-Ncho biết rằng tiến trình con đã bị chấm dứt bởi tín hiệuN(chỉ POSIX).Đối với các quy trình được tạo bằng
create_subprocess_shell(), mã trả về phản ánh trạng thái thoát của chính shell (ví dụ:/bin/sh), có thể ánh xạ tín hiệu tới các mã như128+N. Xem tài liệu về shell (ví dụ: Trạng thái thoát của hướng dẫn sử dụng Bash) để biết chi tiết.
Quy trình con và chủ đề¶
Theo mặc định, vòng lặp sự kiện asyncio tiêu chuẩn hỗ trợ chạy các quy trình con từ các luồng khác nhau.
Trên các quy trình con của Windows chỉ được cung cấp bởi ProactorEventLoop (mặc định), SelectorEventLoop không hỗ trợ quy trình con.
Lưu ý rằng việc triển khai vòng lặp sự kiện thay thế có thể có những hạn chế riêng; vui lòng tham khảo tài liệu của họ.
Xem thêm
Ví dụ¶
Một ví dụ sử dụng lớp Process để điều khiển một quy trình con và lớp StreamReader để đọc từ đầu ra tiêu chuẩn của nó.
Quy trình con được tạo bởi hàm create_subprocess_exec()
nhập asyncio
hệ thống nhập khẩu
không đồng bộ get_date():
code = 'nhập ngày giờ dưới dạng dt; print(dt.datetime.now())'
# Create quy trình con; chuyển hướng đầu ra tiêu chuẩn
# into một cái ống.
proc = đang chờ asyncio.create_subprocess_exec(
sys.executable, '-c', mã,
stdout=asyncio.subprocess.PIPE)
# Read một dòng đầu ra.
dữ liệu = đang chờ proc.stdout.readline()
line = data.decode('ascii').rstrip()
# Wait để thoát khỏi quy trình con.
đang chờ proc.wait()
dòng trở về
ngày = asyncio.run(get_date())
print(f"Ngày hiện tại: {date}")
Xem thêm same example được viết bằng API cấp thấp.