2009-07-10 62 views
4

我希望能够在python中产生一个进程并进行双向通信。当然,Pexpect这样做,确实是我可能走的一条路。但是,这不太理想。Python子流程问题

我的理想情况是有一个跨平台的通用技术,只涉及标准的python库。子进程变得非常接近,但事实上,我不得不等待进程在安全地与之交互之前终止。

看看文档,它确实说有一个stdin,stdout和stderr文件描述符,我可以直接操作,但有一个很大的警告说“不要这样做”。不幸的是,它不完全清楚为什么这个警告存在,但从我从谷歌收集的是,它与os缓冲有关,并且有可能编写代码,当那些内部缓冲区失败时意外死锁(作为附注,任何示例显示错误的方式和正确的方式将不胜感激)。

因此,冒着我的代码潜在的死锁风险,我认为使用poll或select来交互式地从正在运行的进程读取而不杀死它可能会很有趣。虽然我失去了(我认为)跨平台的能力,但我喜欢它不需要额外的库。但更重要的是,我想知道这是否是一个好主意。我还没有尝试这种方法,但我担心可能会破坏我的程序的陷阱。它可以工作吗?我应该测试什么?

在我的具体情况下,我并不是真的担心能够写入流程,只是反复阅读它。另外,我不希望我的流程倾倒大量的文本,所以我希望避免死锁问题,但是我想知道这些限制是什么,并且能够编写一些测试以查看它发生故障的位置。

+0

哎呀!我所有的希望和梦想似乎都被标准输出缓冲所粉碎!为什么不通过操作系统只给我一点点:< – Voltaire 2009-07-11 04:14:44

+0

你在调用一些外部的第三方工具,Python没有模块/库? – ghostdog74 2009-07-13 00:00:35

+0

在某种程度上,是的。幸运的是,这些恰巧在我的控制之下,所以我在我的解决方案中有一些灵活性。如果被调用的脚本刷新了标准输出,那么我可以交互地处理它。理想情况下,我希望我可以制作无缓冲的流,但这似乎是不可能的。 – Voltaire 2009-07-13 16:22:08

回答

0

简单的答案是,没有这样的东西作为流程管理的良好跨平台系统,没有将这个概念设计到您的系统中。这在标准图书馆尤其如此。即使各种unix版本也有自己的兼容性问题。

最好的办法是用适当的事件处理工具处理所有进程,以注意来自任何IPC系统在任何平台上工作得最好的事件。命名管道 将是您描述的问题的一般路线,但在每个平台上将存在执行 的差异。

1

我在一个单独的线程中使用消息队列在线程之间进行通信。在我的情况下,子进程将%完成打印到标准输出。我想让主线建立一个漂亮的进度条。

if sys.platform == 'win32': 
     self.shell = False 
     self.startupinfo = subprocess.STARTUPINFO() 
     self.startupinfo.dwFlags = 0x01 
     self.startupinfo.wShowWindow = 0 
    else: 
     self.shell = True 
     self.startupinfo = None 

。 。 。

f = subprocess.Popen(cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, env = env, shell = self.shell, startupinfo = self.startupinfo) 
    f.stdin.close() 
    line = '' 
    while True: 
     log.debug('reading') 
     c = f.stdout.read(1) 

     log.debug(c) 

     if len(c) == 0: 
      log.info('stdout empty; must be done') 
      break; 
     if ord(c) == 13: 
      continue 
     if c == '%': 
      # post % complete message to waiting thread. 
      line = '' 
     else: 
      line += c 


    log.info('checking for errors') 
    errs = f.stderr.readlines() 

    if errs: 
     prettyErrs = 'Reported Errors: ' 
     for i in errs: 
      prettyErrs += i.rstrip('\n') 

     log.warn(prettyErrs) 
     #post errors to waiting thread 
    else: 
     print 'done'   
    return