Python多进程 - subprocess & multiprocess
Posted __i视觉__(self, 知识库):
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python多进程 - subprocess & multiprocess相关的知识,希望对你有一定的参考价值。
1. subprocess
该模块主要用于调用子程序
。
- multiprocess: 是同一个代码中通过多进程调用其他的模块(也是自己写的)
- subprocess: 直接调用外部的二进制程序,而非代码模块
1.1. Popen
p.poll() # 检查进程是否终止,如果终止返回returncode,否则返回None
p.wait(timeout) # 等待子进程终止(阻塞父进程)
p.communicate(input,timeout) # 和子进程交互,发送和读取数据(阻塞父进程)
p.send_signal(singnal) # 发送信号到子进程
p.terminate() # 停止子进程,也就是发送SIGTERM信号到子进程
p.kill() # 杀死子进程。发送SIGKILL信号到子进程
创建Popen对象后,主程序不会自动等待子进程完成。
以上三个成员函数都可以用于等待子进程返回:while循环配合Popen.poll()、Popen.wait()、Popen.communicate()。由于后面二者都会阻塞父进程,所以无法实时获取子进程输出,而是等待子进程结束后一并输出所有打印信息。另外,Popen.wait()、Popen.communicate()分别将输出存放于管道和内存,前者容易超出默认大小而导致死锁,因此不推荐使用。
注意:p.communicate(stdin="xxx")
该函数会终止子程序(因为其是阻塞的,当父程序解除阻塞时,意味着子程序已经结束了)。所以,如果你的子程序是 while...
或者 for line in sys.stdin
时,你会发现子程序意外的结束了,而不是在循环中等待。
1.1.1. 管理子进程(通信)
Popen类具有三个与输入输出相关的属性:Popen.stdin
, Popen.stdout
和 Popen.stderr
,分别对应子进程的标准输入/输出/错误。它们的值可以是PIPE、文件描述符(正整数)、文件对象或None:
- PIPE表示创建一个连接子进程的新管道,默认值None, 表示不做重定向。
- 子进程的文件句柄可以从父进程中继承得到。
- 仅
stderr
可以设置为STDOUT
,表示将子进程的标准错误重定向到标准输出。
child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["wc"], stdin=child1.stdout, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out = child2.communicate()
其中,subprocess.PIPE为文本流提供一个缓存区,child1的stdout将文本输出到缓存区;随后child2的stdin从该PIPE读取文本,child2的输出文本也被存放在PIPE中,而标准错误信息则重定向到标准输出;最后,communicate()方法从PIPE中读取child2子进程的标准输出和标准错误。
注意:subprocess.stdxxx
操作bytes字节,而 sys.stdin
则是string。
sys.stdin
Python的sys模块定义了标准输入/输出/错误:
sys.stdin # 标准输入
sys.stdout # 标准输出
sys.stderr # 标准错误信息
以上三个对象类似于文件流,因此可以使用readline()和write()方法进行读写操作。也可以使用print(),等效于sys.stdout.write()。
需要注意的是,除了直接向控制台打印输出外,标准输出/错误的打印存在缓存,为了实时输出打印信息,需要执行
sys.stdout.flush()
sys.stderr.flush()
读取 sys.stdin
的方式:
for line in sys.stdin:
print(type(line)) # string
...
示例
前面提到,如果子程序只是调用一次,并获取其输出状态,可以使用 p.communicate(stdin, timeout)
结合 p.returncode
实现。
但如果你的程序想实现类似 TCP-C/S 式的持续通信服务,这里提供一个Demo:
父程序:
proc = subprocess.Popen(command,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
# stderr=subprocess.STDOUT)
# try:
while proc.poll() is None: # 持续输入
str_input = input("Please Input a path: ")
if str_input == "quit":
break
bytes_path = f"/home/brt/{str_input}.jpg
".encode() # 注意这里需要
换行符
proc.stdin.write(bytes_path) # 需要使用bytes
proc.stdin.flush()
# proc.communicate(stdin=str_input, timout=5)
bytes_state = proc.stdout.readline() # bytes
if bytes_state == b"ok
":
print("Well Done.")
# except subprocess.TimeoutExpired:
# print("子程序Timout未响应...")
# break
# if proc.poll() is None: # communicate()超时时,子程序可能未退出
# proc.kill()
子程序:
for path_save in sys.stdin: # 持续读取
path_save = path_save.strip() # 删除多余的换行符
img = grabclipboard_byQt(cb)
# sys.stderr.write(">>>", img)
if img:
save_clipboard_image(img, path_save)
str_pipe = "ok"
else:
str_pipe = ""
# 以下内容用于写入stdout管道,向父程序反馈
# sys.stdout.write(str_pipe + "
") # 必须添加换行符
print(str_pipe)
sys.stdout.flush() # 及时清空缓存
2. multiprocess
!-- +++ title>以上是关于Python多进程 - subprocess & multiprocess的主要内容,如果未能解决你的问题,请参考以下文章
2022-04-11 - Python multiprocessing subprocess 模块区别
Python标准库10 多进程初步 (multiprocessing包)