相关文章推荐
威武的蘑菇  ·  【小米手机代号】xiaomi和redmi手机 ...·  2 周前    · 
重情义的筷子  ·  地平线机器人上市首日股价涨幅冲高收窄,智驾芯 ...·  4 月前    · 
逆袭的围巾  ·  《梦幻西游》电脑版官方网站 - ...·  1 年前    · 
飞翔的投影仪  ·  全面推进中国特色大国外交_中华人民共和国外交部·  1 年前    · 
越狱的刺猬  ·  SpringBoot+mybaties启动异 ...·  1 年前    · 
Code  ›  用python3 中的subprocess写一个简单的守护进程_python subprocess 守护进程_Idea King的博客
https://blog.csdn.net/besmarterbestronger/article/details/94738845
打篮球的充值卡
2 年前
  • 1. 简单介绍
    • 1.1. subprocess
      • 1.1.1. subprocess.run()
        • subprocess.CompletedProcess
        • 可能会用到的一些值
      • 1.1.3. subprocess.Popen
    • 2. 代码实例
    • 3. 参考文献

    1. 简单介绍

    1.1. subprocess

    subprocess模块可以生成新进程,连接到它们的输入/输出/错误管道,并能够获取它们的返回码。 该模块旨在替换几个较旧的模块和功能:

    os.system
    os.spawn*
    os.popen*
    popen2.*
    commands.*
    

    1.1.1. subprocess.run()

    在很多时候,使用subprocess.run()就够了。

    subprocess.run(
    	args,  # 所需要运行的shell命令
    	stdin=None,  # 
    	input=None,  # input参数会传递给Popen.communicate(),从而传递给subprocess的stdin。
    	stdout=None,  # 捕获子进程的标准输出,若没捕获到,则输出None
    	stderr=None,   # 捕获子进程的标准错误,若没捕获到,则输出None
    	shell=False,  #  如果shell为True,那么指定的命令将通过shell执行。如果我们需要访问某些shell的特性,如管道、文件名通配符、环境变量扩展功能,这将是非常有用的
    	timeout=None,  # timeout参数会传递给Popen.communicate()。如果超时,子进程将被终止并等待。 子进程终止后,将重新引发TimeoutExpired异常。
    	check=False # 如果check是True,  而且进程退出时的返回码不是0,那么就会引发CalledProcessError异常。该异常的属性包含参数,退出代码以及stdout和stderr(如果它们被捕获)。
    当通过subprocess.run()运行的命令结束之后,会返回一个CompletedProcess实例。
    

    subprocess.run的例子

    In[1]: subprocess.run(["ls", "-l"])  # 不捕获输出
    总用量 40
    -rw-r--r-- 1 sjl sjl   280 6月  28 18:53 01_lei_jicheng.py
    -rw-r--r-- 1 sjl sjl   329 6月  28 20:40 02_huode_mulu_suoyou_wenjian.py
    -rw-r--r-- 1 sjl sjl   399 6月  28 20:52 03_yichang_buhuo.py
    -rw-r--r-- 1 sjl sjl   197 7月   1 16:39 04_bibao_yanci.py
    -rw-r--r-- 1 sjl sjl   705 7月   2 19:01 05_qingwa_tiao_taijie.py
    -rw-r--r-- 1 sjl sjl  2555 6月  25 17:43 construct.py
    -rw-r--r-- 1 sjl sjl   945 6月  24 20:19 re_construct.py
    -rw-r--r-- 1 sjl sjl 10674 7月   5 15:35 record.txt
    Out[3]: CompletedProcess(args=['ls', '-l'], returncode=0)
    In[2]: subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
    Out[2]: CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0, stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')
    In[3]: subprocess.run(["ls", "-l"], stdout=subprocess)
    Out[3]:  CompletedProcess(args=['ls', '-l'], returncode=0, stdout=b'\xe6\x80\xbb\xe7\x94\xa8\xe9\x87\x8f 40\n-rw-r--r-- 1 sjl sjl   280 6\xe6\x9c\x88  28 18:53 01_lei_jicheng.py\n-rw-r--r-- 1 sjl sjl   329 6\xe6\x9c\x88  28 20:40 02_huode_mulu_suoyou_wenjian.py\n-rw-r--r-- 1 sjl sjl   399 6\xe6\x9c\x88  28 20:52 03_yichang_buhuo.py\n-rw-r--r-- 1 sjl sjl   197 7\xe6\x9c\x88   1 16:39 04_bibao_yanci.py\n-rw-r--r-- 1 sjl sjl   705 7\xe6\x9c\x88   2 19:01 05_qingwa_tiao_taijie.py\n-rw-r--r-- 1 sjl sjl  2555 6\xe6\x9c\x88  25 17:43 construct.py\n-rw-r--r-- 1 sjl sjl   945 6\xe6\x9c\x88  24 20:19 re_construct.py\n-rw-r--r-- 1 sjl sjl 10674 7\xe6\x9c\x88   5 15:35 record.txt\n')
    

    subprocess.CompletedProcess

    它是subprocess.run()的返回值,表明一个进程已经完成。

    可能会用到的一些值

    subprocess.DEVNULL:可以作为popen()中stdin, stdout 或 stderr的一个特殊值,表明特殊文件os.devnull将会被使用
    subprocess.PIPE :可以作为popen()中stdin, stdout 或 stderr的一个特殊值,表明一个标准流的管道会打开,最适用于popen.communicate()
    subprocess.STDOUT:可以作为popen()中stderr的一个特殊值,表示标准错误应与标准输出进入相同的句柄。
    exception subprocess.SubprocessError:此模块中其他异常类的基类。
    exception subprocess.TimeoutExpired:SubprocessError的子类,在等待子进程时超时时引发。
    exception subprocess.CalledProcessError:SubprocessError子类,当check_call()或check_output()运行的进程返回非零状态码时引发。
    

    1.1.3. subprocess.Popen

    和subprocess.run()相比而言,subprocess.popen是一个更底层的接口,它具有非常高的灵活性,能够处理一些不太常见的情况。使用subprocess.Popen()会在新进程中执行子程序。在POSIX上,该类使用os.execvp()的类似行为来执行子程序。在Windows上,该类使用Windows CreateProcess() 函数。

    subprocess.Popen(	args, bufsize=-1,	executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, 
    cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, 	pass_fds=())
    	args, # 需要执行的参数序列,或者是单个的字符串参数。如果是序列,默认执行序列中的第一项,若是字符串,则跟你使用的系统有关。通常情况args作为序列来使用。
    	bufsize=-1, # 在创建stdin / stdout / stderr管道文件对象时,bufsize作为open()函数的相应参数。0表示无缓冲,1表示线缓冲
    	(仅当universal_newlines = True时才可用,即在文本模式下), 其它正值表示使用的缓冲区的大小,负值表示使用系统默认的io.DEFAULT_BUFFER_SIZE。
    	executable=None, # 指明了需要执行的替代程序,一般很少使用。当sell=False时,executable会代替要执行的args。但是最初的args仍然会传递给
    	程序。大多程序将args作为命令的名称,这与真正执行的命令不同。
    	stdin=None,  # 表明程序的标准输入,有效值是PIPE,DEVNULL,存在的文件描述符,存在的文件对象和None
    	stdout=None,  # 表明程序的标准输出,有效值是PIPE,DEVNULL,存在的文件描述符,存在的文件对象和None
    	stderr=None,  # 表明程序的标准错误,有效值是PIPE,DEVNULL,存在的文件描述符,存在的文件对象和None
    	preexec_fn=None,  # 弱preexec_fn设置为一个可调用对象,该子进程会在执行之前调用此对象
    	close_fds=True, #如果close_fds为True,则在执行子进程之前将关闭除0,1和2之外的所有文件描述符。
    	shell=False
    
    
    
    
        
    , # 默认为False,表示是否使用shell来执行程序。如果shell为True 推荐args使用字符串而不是序列。在POSIX上,shell = True,shell默
    	认是/ bin / sh。 如果args是一个字符串,则该字符串指定要通过shell执行的命令。 这意味着字符串的格式必须与在shell提示符下键入时完全相
    	同。例如,引用或反斜杠转义带有空格的文件名。 如果args是一个序列,则第一个项指定命令字符串,并且任何其他项将被视为shell本身的附加参
    	数。 等价于 Popen(['/bin/sh', '-c', args[0], args[1], ...])
    	cwd=None, # 如果cwd不是None,则该函数在执行子进程之前将工作目录更改为cwd。
    	env=None, # 如果env不是None,则它必须是定义新进程的环境变量的映射; 这些用于代替继承当前进程环境的默认行为。
    	universal_newlines=False, # 如果universal_newlines为True,则文件对象stdin,stdout和stderr在通用换行模式下作为文本流打开,
    	startupinfo=None, # 若制定了startupinfo,则会将一个STARTUPINFO对象传递给底层的CreateProcess函数。
    	creationflags=0, # 通常为 CREATE_NEW_CONSOLE 或CREATE_NEW_PROCESS_GROUP(windows下)
    	restore_signals=True, # Python设置为SIG_IGN的所有信号都会在exec之前的子进程中恢复为SIG_DFL。 目前,这包括SIGPIPE,SIGXFZ和SIGXFSZ信号。
    	start_new_session=False,  # 若为True,则会在subprocess执行子进程之前创建stdid()系统。
    	pass_fds=() # pass_fds是一个可选的文件描述符序列,用于在父项和子项之间保持打开状态。 只要使用pass_fds,则close_fds会被强制设为True。
    

    通过with语句支持Popen对象作为上下文管理器:退出时,将关闭标准文件描述符,并等待进程。

    with Popen(["ifconfig"], stdout=PIPE) as proc:
        log.write(proc.stdout.read())
    

    Popen类有如下这些实例方法:

    # 检查子进程是否已终止。 设置并返回returncode属性。
    Popen.poll() 
    # 等待子进程终止。 设置并返回returncode属性。如果进程在超时秒后没有终止,则引发TimeoutExpired异常。 然后捕获此异常并重试等待。
    Popen.wait(timeout=None)
    # 与进程交互:将数据发送到stdin。 从stdout和stderr读取数据,直到达到文件结尾(eof)。 等待进程终止。
    # 可选的输入参数应该是要发送到子进程的数据,如果没有数据则应该是None。 输入类型必须是字节,如果universal_newlines为True,则为字符串。
    # communic() 返回一个元组(stdout_data,stderr_data)。 数据类型是字节,如果universal_newlines为True,则为字符串。
    Popen.communicate(input=None, timeout=None)
    proc = subprocess.Popen(...)
    try:
        outs, errs = proc.communicate(timeout=15)
    except TimeoutExpired:
        proc.kill()
        outs, errs = proc.communicate()
    # 发送signal信号给子进程。
    Popen.send_signal(signal)
    # 停止子进程。 在Posix操作系统中,该方法将SIGTERM发送给子进程。 在Windows中,调用Win32 API函数TerminateProcess() 来停止子进程。
    Popen.terminate()
    # 杀死子进程。在Posix操作系统中,此函数将会发送SIGKILL给子进程。在windows中 kill() 是teminate()的一个别名。
    Popen.kill()
    # args参数传递给Popen  - 为序列或单个字符串。
    Popen.args
    # 如果stdin参数是PIPE,则此属性是open()返回的可写流对象。 如果universal_newlines参数为True,则流是文本流,否则它是字节流。
    # 如果stdin参数不是PIPE,则此属性为None。
    Popen.stdin
    # 如果stdout参数是PIPE,则此属性是open()返回的可读流对象。 从流中读取提供子进程的输出。 如果universal_newlines参数为True,
    # 则流是文本流,否则它是字节流。 如果stdout参数不是PIPE,则此属性为None。
    Popen.stdout
    #如果stderr参数是PIPE,则此属性是open()返回的可读流对象。 从流中读取提供了子进程的错误输出。 如果universal_newlines参数为True,
    # 则流是文本流,否则它是字节流。 如果stderr参数不是PIPE,则此属性为None。
    Popen.stderr
    # 子进程的进程id。请注意,如果将shell参数设置为True,则这是生成的shell的进程ID
    Popen.pid
    # 子进程的返回码,通常由poll()或wait()来指定返回码的值,若为None表明该子进程尚未终止。
    Popen.returncode
    

    2. 代码实例

    #coding:utf-8
    #/usr/bin/env python
    # author:sjl
    # created:2019/04/23
    # update: 2019/04/25
    # desc: 守护进程,指定py程序挂掉后自动重启。
    # filename: my_deamon.py
    import os
    import sys
    import time
    import datetime
    import psutil
    import subprocess
    TIME = 1
    CMD = "test.py" # 你所要执行的命令
    class MyDeamon(object):
    	def __init__(self, sleep_time, cmd):
    		self.sleep_time = sleep_time # 休息时间
    		self.cmd = cmd # 需要执行的命令
    		self.p = None # 子进程对象
    		self.run() # 调用run()方法
    	def check(self):
    		try:
    			while True:
    				time.sleep(self.sleep_time * 60)
    				# self.pid = os.popen('ps -ef | grep {}'.format(self.cmd)).readlines()[0].split()[1] # str类型
    				self.pid = self.p.pid # 查看子进程的进程id
    				self.poll = self.p.poll()  # returncode 返回码
    				if self.poll: # self.poll不为None, 表明子进程终止了
    						print("程序已终止,重启程序")
    						self.p.kill()
    						self.run()
    				else:
    					print("[{}] 程序正在运行中".format(datetime.datetime.now()))
    		except KeyboardInterrupt as e: # 
    			print("[{}] 监测到ctrl+c,准备退出程序".format(datetime.datetime.now()))
    			self.p.kill()
    	def run(self):
    		if self.cmd.endwith('.py'): # 运行.py文件
    			print("[{}] 开始运行子进程!".format(datetime.datetime.now()))
    			# 使用subprocess.Popen()创建一个子进程运行你的py文件
    			self.p = subprocess.Popen(['python3', '{}'.format(self.cmd)], stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr,shell=False) 
    		else:
    			print("{}] 请运行py文件!".format(datetime.datetime.now()))
    if __name__ == '__main__':
    	app = MyDeamon(TIME, CMD)
    	app.check()
    

    3. 参考文献

    [1] subprocess官方文档
    [2] python的subprocess模块

    目录1. 简单介绍1.1. psutil1.2. subprocess1.2.1. subprocess.run()subprocess.CompletedProcess可能会用到的一些值1.2.3. subprocess.Popen4. 代码实例5. 参考文献1. 简单介绍通过使用python中的psutil库和subprocess库,实现了一个守护进程。1.1. psutil1.2. ... 1.1 守护进程 守护进程是系统中生存期较长的一种进程,常常在系统引导装入时启动,在系统关闭时终止,没有控制终端,在后台运行。守护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的终端信息所打断。 在这里,我们在Linux2.6内核的centos中,ps -ef |awk '{print $1"\t "$2"\t "$3"
    进程是资源分配的最小单位,线程是CPU调度的最小单位。 每一个进程启动时都会最先产生一个线程,即主线程。然后主线程会再创建其他的子线程。 与进程相关的资源包括:内存页(同一个进程中的所有线程共享同一个内存空间);文件描述符(e.g. open sockets);安全凭证(e.g.启动该进程的用户ID) GIL(Global Interpreter Lock,全局解释器锁) 在非python环境中,单核情况下,同时只能有一个任务执行。多核时可以支持多个线程同时执行。但是在python中,无论有多少核,同时.
    参考文章:https://www.cnblogs.com/lincappu/category/1140217.html 1.1 线程、多线程 线程是一个基本的 CPU 执行单元。它必须依托于进程存活。一个线程是一个execution context(执行上下文),即一个 CPU 执行时所需要的一串指令。 多线程共享同个地址空间、打开的文件以及其他资源。 线程的类型:主线程、子线程、... 运行并等待args参数指定的指令完成,返回CompletedProcess实例。 参数:(*popenargs, input=None, capture_output=False, timeout=None, check=False, **kwargs)。除input, capture_output, timeout, check,其他参数与Popen构造器参数一致。 capture_output:如果设置为True,表示重定向stdout和stderr到管道,且不能
    5. python实现多进程 Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次返回一次,但是fork()调用一次返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后分别在父进程和子进程内返回。 子进程永远返回0,而父进程返回进程的ID。一个父进程可以fork出多个子进程,所以父进程要记下每个子进程的ID,而子进程只主要调用getppid()就可以拿到父进程的ID。 父进程、子进程执行的顺序没有规律,完全取决于操作系统的调度
    # 执行命令 p = subprocess.Popen(['python'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # 与用户交互 while True: # 获取用户输入 user_input = input('> ') # 将用户输入发送给子进程 p.stdin.write(user_input.encode()) p.stdin.write(b'\n') p.stdin.flush() # 从子进程获取输出 output = p.stdout.readline().decode().strip() # 输出子进程的响应 print(output) 这个代码会启动一个Python子进程,并与用户交互。用户可以输入任何Python代码,子进程会执行并返回结果。
 
推荐文章
威武的蘑菇  ·  【小米手机代号】xiaomi和redmi手机型号英文代号查询大全 - 系统帝国网
2 周前
重情义的筷子  ·  地平线机器人上市首日股价涨幅冲高收窄,智驾芯片龙头还需解决亏损问题
4 月前
逆袭的围巾  ·  《梦幻西游》电脑版官方网站 - 网易西游题材扛鼎之作
1 年前
飞翔的投影仪  ·  全面推进中国特色大国外交_中华人民共和国外交部
1 年前
越狱的刺猬  ·  SpringBoot+mybaties启动异常javax.xml.parsers.DocumentBuilderFactory.setFeature(Ljava/lang/String;Z)V异常_m
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号