2023年8月1日发(作者:)
Python多进程(1)——subprocess与Popen() Python多进程⽅⾯涉及的模块主要包括:;;multiprocessing:提供⽀持多处理器技术的多进程编程接⼝,并且接⼝的设计最⼤程度地保持了和threading模块的⼀致,便于理解和使⽤。
本⽂主要介绍 subprocess 模块及其提供的 Popen 类,以及如何使⽤该构造器在⼀个进程中创建新的⼦进程。此外,还会简要介绍 subprocess 模块提供的其他⽅法与属性,这些功能上虽然没有 Popen 强⼤的⼯具,在某些情况下却⾮常⽅便和⾼效。 本⽂的⽬录如下: 1. 类 2. Popen 对象的属性 3. Popen 对象的⽅法 4. subprocess模块的其他简便⽅法 5. subprocess模块的其他属性 6. subprocess模块定义的异常
类 通过调⽤:(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0) 创建并返回⼀个⼦进程,并在这个进程中执⾏指定的程序。 实例化 Popen 可以通过许多参数详细定制⼦进程的环境,但是只有⼀个参数是必须的,即位置参数 args ,下⾯也会详细介绍剩余的具名参数。参数介绍:args:要执⾏的命令或可执⾏⽂件的路径。⼀个由字符串组成的序列(通常是列表),列表的第⼀个元素是可执⾏程序的路径,剩下的是传给这个程序的参数,如果没有要传给这个程序的参数,args 参数可以仅仅是⼀个字符串。bufsize:控制 stdin, stdout, stderr 等参数指定的⽂件的缓冲,和打开⽂件的 open()函数中的参数 bufsize 含义相同。executable:如果这个参数不是 None,将替代参数 args 作为可执⾏程序;stdin:指定⼦进程的标准输⼊;stdout:指定⼦进程的标准输出;stderr:指定⼦进程的标准错误输出; 对于 stdin, stdout 和 stderr ⽽⾔,如果他们是 None(默认情况),那么⼦进程使⽤和⽗进程相同的标准流⽂件。 ⽗进程如果想要和⼦进程通过 communicate() ⽅法通信,对应的参数必须是 (见下⽂例4); 当然 stdin, stdout 和 stderr 也可以是已经打开的 file 对象,前提是以合理的⽅式打开,⽐如 stdin 对应的⽂件必须要可读等。 preexec_fn:默认是None,否则必须是⼀个函数或者可调⽤对象,在⼦进程中⾸先执⾏这个函数,然后再去执⾏为⼦进程指定的程序或Shell。close_fds:布尔型变量,为 True 时,在⼦进程执⾏前强制关闭所有除 stdin,stdout和stderr外的⽂件;shell:布尔型变量,明确要求使⽤shell运⾏程序,与参数 executable ⼀同指定⼦进程运⾏在什么 Shell 中——如果executable=None ⽽ shell=True,则使⽤ /bin/sh 来执⾏args 指定的程序;也就是说,Python⾸先起⼀个shell,再⽤这个shell来解释指定运⾏的命令。cwd:代表路径的字符串,指定⼦进程运⾏的⼯作⽬录,要求这个⽬录必须存在;env:字典,键和值都是为⼦进程定义环境变量的字符串;universal_newline:布尔型变量,为 True 时,stdout 和 stderr 以通⽤换⾏(universal newline)模式打开,startupinfo:见下⼀个参数;creationfalgs:最后这两个参数是Windows中才有的参数,传递给Win32的CreateProcess API调⽤。 同 Linux 中创建⼦进程类似,⽗进程创建完⼦进程后,并不会⾃动等待⼦进程执⾏,⽗进程在⼦进程之前推出将导致⼦进程成为孤⼉进程,孤⼉进程统⼀由 init 进程接管,负责其终⽌后的回收⼯作。 如果⽗进程在⼦进程之后终⽌,但⼦进程终⽌时⽗进程没有进⾏最后的回收⼯作,⼦进程残留的数据结构称为僵⼫进程。⼤量僵⼫进程将耗费系统资源,因此⽗进程及时等待和回收⼦进程是必要的,除⾮能够确认⾃⼰⽐⼦进程先终⽌,从⽽将回收⼯作过渡给 init 进程。 这个等待和回收⼦进程的操作就是wait()函数,下⽂中将会介绍。例1: 创建⼀个⼦进程,然后执⾏⼀个简单的命令>>> import subprocess>>> p = ('ls -l', shell=True)>>> total 164-rw-r--r-- 1 root root 133 Jul 4 16:25 -rw-r--r-- 1 root root 268 Jul 10 15:55 ...>>> code>>> ()0>>> code0 这⾥也可以使⽤ p = (['ls', '-cl']) 来创建⼦进程。
Popen 对象的属性 Popen创建的⼦进程有⼀些有⽤的属性,假设 p 是 Popen 创建的⼦进程,p 的属性包括:1.
⼦进程的PID。 2.
code 该属性表⽰⼦进程的返回状态,returncode可能有多重情况:None —— ⼦进程尚未结束;==0 —— ⼦进程正常退出;> 0—— ⼦进程异常退出,returncode对应于出错码;< 0—— ⼦进程被信号杀掉了。 3.
, , ⼦进程对应的⼀些初始⽂件,如果调⽤Popen()的时候对应的参数是,则这⾥对应的属性是⼀个包裹了这个管道的 file 对象, Popen 对象的⽅法() 检查⼦进程 p 是否已经终⽌,返回 code 属性 (参考下⽂ Popen 对象的属性);() 等待⼦进程 p 终⽌,返回 code 属性; 注意: wait() ⽴即阻塞⽗进程,直到⼦进程结束!icate(input=None) 和⼦进程 p 交流,将参数 input (字符串)中的数据发送到⼦进程的 stdin,同时从⼦进程的 stdout 和 stderr 读取数据,直到EOF。 返回值: ⼆元组 (stdoutdata, stderrdata) 分别表⽰从标准出和标准错误中读出的数据。 ⽗进程调⽤ icate() 和⼦进程通信有以下限制: (1) 只能通过管道和⼦进程通信,也就是说,只有调⽤ Popen() 创建⼦进程的时候参数 stdin=,才能通过 icate(input) 向⼦进程的 stdin 发送数据;只有参数 stout 和 stderr 也都为 ,才能通过icate() 从⼦进程接收数据,否则接收到的⼆元组中,对应的位置是None。 (2)⽗进程从⼦进程读到的数据缓存在内存中,因此commucate()不适合与⼦进程交换过⼤的数据。 注意: communicate() ⽴即阻塞⽗进程,直到⼦进程结束!_signal(signal) 向⼦进程发送信号 signal;ate() 终⽌⼦进程 p ,等于向⼦进程发送 SIGTERM 信号;() 杀死⼦进程 p ,等于向⼦进程发送 SIGKILL 信号;
subprocess模块的其他⽅法1.
(args, *, stdin=None, stdout=None, stderr=None, shell=False) ⽗进程直接创建⼦进程执⾏程序,然后等待⼦进程完成 返回值: call() 返回⼦进程的 退出状态 即 code 属性;2.
_call(args, *, stdin=None, stdout=None, stderr=None, shell=False) ⽗进程直接创建⼦进程执⾏程序,然后等待⼦进程完成,具体可以使⽤的参数,参考上⽂ Popen 类的介绍。 返回值: ⽆论⼦进程是否成功,该函数都返回 0;但是 如果⼦进程的退出状态不是0,check_call() 抛出异常 CalledProcessError,异常对象中包含了 code 对应的返回码。例2: check_call()正常与错误执⾏命令>>> p = _call(['ping' ,'-c', '2', ''])PING (220.181.111.188) 56(84) bytes of data.64 bytes from 220.181.111.188: icmp_seq=1 ttl=42 time=37.4 ms64 bytes from 220.181.111.188: icmp_seq=2 ttl=42 time=37.3 ms--- ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 1001msrtt min/avg/max/mdev = 37.335/37.410/37.486/0.207 ms>>> print p0>>> p = _call(['ping' ,'-c', '4', 'www.!@$#@!(*^.com'])ping: unknown host www.!@$#@!(*^.comTraceback (most recent call last): File "
注意: 使⽤上⾯提到的三个⽅法:call()、check_call() 和 check_output() 时,尽量不要将参数 stderr 和 stdout 设置为 ,这⼏个函数默认都会等待⼦进程完成,⼦进程产⽣⼤量的输出数据如果造成管道堵塞,⽗进程再等待⼦进程完成可能造成死锁。 subprocess模块的其他属性 调⽤本模块提供的若⼲函数时,作为 std* 参数的值,为标准流⽂件打开⼀个管道。例4: 使⽤管道连接标准流⽂件import subprocesschild1 = (['ls', '-l'], stdout=)child2 = (['wc', '-l'], stdin=, stdout=)out = icate()()()print(out) 这⾥将⼦进程 child1 的标准输出作为⼦进程 child2 的标准输⼊,⽗进程通过 communicate() 读取 child2 的标准输出后打印。
调⽤本模块提供的若⼲函数时,作为 stderr 参数的值,将⼦进程的标准错误输出打印到标准输出。
subprocess模块定义的异常exception ProcessError (1)什么时候可能抛出该异常:调⽤ check_call() 或 check_output() ,⼦进程的退出状态不为 0 时。 (2)该异常包含以下信息:returncode:⼦进程的退出状态;cmd:创建⼦进程时指定的命令;output:如果是调⽤ check_output() 时抛出的该异常,这⾥包含⼦进程的输出,否则该属性为None。
总结 本⽂介绍了Python subprocess的基本⽤法,使⽤ Popen 可以在Python进程中创建⼦进程,如果只对⼦进程的执⾏退出状态感兴趣,可以调⽤ () 函数,如果想通过异常处理机制解决⼦进程异常退出的情形,可以考虑使⽤ _call() 和 _output。如果希望获得⼦进程的输出,可以调⽤_output(),但 Popen() ⽆疑是功能最强⼤的。 subprocess模块的缺陷在于默认提供的⽗⼦进程间通信⼿段有限,只有管道;同时创建的⼦进程专门⽤来执⾏外部的程序或命令。 Linux下进程间通信的⼿段很多,⼦进程也完全可能从创建之后继续调⽤
发布者:admin,转转请注明出处:http://www.yc00.com/web/1690875282a452448.html
评论列表(0条)