新浪博客

python win subprocess模块popen 开启关闭新控制台/使用管道及关闭子进程(ffmpeg相关)

2018-01-09 03:01阅读:

python win subprocess模块popen 如何开启关闭新控制台/使用管道及关闭子进程(ffmpeg相关)

  • 结论
    • 使用python的subprocess模块(windows环境下)
      1. 如何调用ffmpeg并作为守护进程(支持ffmpeg命令中使用管道)
        1. 在新控制台/新窗口里显示(但无法在新控制台里输入)
          process = subprocess.Popen('cmd', creationflags=subprocess.CREATE_NEW_CONSOLE, stdin=subprocess.PIPE)
          process.stdin.write(('%s' % ffmpeg_cmd).encode('utf-8'))
          #往控制台里写入ffmpeg命令
          #这样执行完ffmpeg命令不会退出,想要调用完自动退出要使用('%s&exit' % ffmpeg_cmd)
          process.stdin.flush()
        2. 不显示新控制台/新窗口
          process = subprocess.Popen(ffmpeg_cmd, shell=True, creationflags=subprocess.CREATE_NEW_CONSOLE)
      2. 如何调用ffmpeg不作为守护进程,随python程序结束(支持ffmpeg命令中使用管道)
        • 复制上面的的命令,去掉creationflags参数,并加上stderr=subprocess.DEVNULL,例如:
          process = subprocess.Popen(ffmpeg_cmd, shell=True, stderr=subprocess.DEVNULL)
#stderr=subprocess.DEVNULL是为了隐藏ffmpeg命令产生的输出,因为ffmpeg将日志都输出在stderr上
#如果不重定向至subprocess.DEVNULL,就会直接输出在python程序所在的控制台上,造成混乱
  • 如何结束/杀掉/终结调用的ffmpeg进程
  1. python的signal模块: os.kill(process.pid, signal.CTRL_C_EVENT),但泛用性小,不推荐
  2. linux下
    • 使用'进程组',相关教程附在《拓展参考》内
  3. windows下
    • windows的taskkill命令
      os.system('taskkill /t /f /pid %s' % process.pid)
      #/t:结束进程树,包括子进程 /f:强制结束 /pid:进程pid
      #可使用其他命令替代os.system
  • 原理
  1. 为何可以使用系统管道?
    • 因为在命令行环境下使用系统管道
    • 所以用Popen('cmd')开启cmd进程,往cmd里写入ffmpeg命令,就可以在命令行环境下使用系统管道
    • 或者shell=True,会开启一个命令行执行命令
    • 可应用于ffmpeg转码给ffplay播放
    • 此处关于shell=True的解释并不准确,详情参考官方文档及各类教程
  2. 为何process.kill()/terminate()无法结束ffmpeg进程?
    • 因为process对应的是执行ffmpeg命令的命令行进程,所以popen返回的pid实际是命令行shell环境的pid
    • 调用kill()只会结束命令行进程而无法结束ffmpeg进程
    • subprocess模块无法结束调用产生的子进程是个大坑,不过耐心搜索还是能找到对应方案
  3. 关于开启新控制台/新窗口,以及上文中使用Popen的相关参数
    • 请参考有关教程,例如以下参数:
    • stdin/stdout/stderr,subprocess.PIPE/DEVNULL/STDOUT
    • shell=True/False
    • creationflags=subprocess.CREATE_NEW_CONSOLE/CREATE_NEW_PROCESS_GROUP
    • 坑爹的startupinfo
  • 参考
  • 拓展参考
  1. 类似的popen调用ffmpeg的情况
  2. CTRL C 信号结束进程
  3. 关于使用popen无法结束子进程的坑
  4. startupinfo相关MSDN文档出处
  5. startupinfo相关
  • 总结对popen打开新终端窗口调用ffmpeg的理解:
  • shell参数默认是False,就是不调用命令行环境解释popen中的命令,效果就是popen中的整条命令当作调用某个具体的程序,所以管道符号被当作程序的参数对待,而没有发挥管道的作用。在这里popen的命令是'cmd'打开终端程序,但是要出现新的终端窗口就要creationflags参数的配合。
  • 当不设置creationflags的时候,popen执行的命令产生的子进程依附于python脚本下,而python脚本依附于终端窗口下(如果是在终端里执行的python脚本),所以子进程和python脚本共享一个终端窗口,所以输出信息会混在一起。当creationflags设置为CREATE_NEW_CONSOLE时,子进程会独立于python脚本,自然就不会共享同一个终端窗口了,配合'cmd'命令,就打开了一个新的独立终端窗口,即使python脚本关闭了,子进程也不会受影响,大概可以算是'守护进程'吧?
  • 这么说的话,直接调用ffmpeg命令岂不是也能产生新的终端窗口?行不行我不记得了,但我需要用到管道符号,所以shell=False的情况下是无法实现的。
  • 那让shell=True不就好了?实验证明这种组合的话,是无法产生新窗口的,现在回想起来我就是被这样的组合坑了良久却百思不得其解为什么没有新窗口。具体原因不知道是什么也不做探究了。
  • 结论是CREATE_NEW_CONSOLE的效果是产生独立的子进程,shell=True是以命令行环境执行命令,两者一起用会无法产生新终端窗口,但运行正常,子进程不会输出在python终端里。

我的更多文章

下载客户端阅读体验更佳

APP专享