简体   繁体   English

subprocess.Popen的奇怪执行模式

[英]Strange execution patterns with subprocess.Popen

I have a Python script wherein a JAR is called. 我有一个Python脚本,其中调用了JAR。 After the JAR is called, two shell scripts are called. 调用JAR后,将调用两个shell脚本。 Initially I was doing this: 最初我这样做:

proc = subprocess.Popen(jar_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
proc.wait()
output, errors = proc.communicate()

proc = subprocess.Popen(prune_command, shell=True)
proc.wait()

proc = subprocess.call(push_command, shell=True)

I have to wait for the first two processes to finish so I use Popen() and the final one I can let it run in the background, so I call() it. 我必须等待前两个进程完成所以我使用Popen()和最后一个我可以让它在后台运行,所以我call()它。 I pass shell=True because I want the called shell scripts to have access to environment variables. 我传递shell=True因为我希望被调用的shell脚本可以访问环境变量。

The above works, however, I don't get any logging from the JAR process. 但是,上面的工作,我没有从JAR进程中获取任何日志记录。 I've tried calling it this way: 我试过这样称呼它:

proc = subprocess.call(jar_command)

This logs as I would expect, but the two shell scripts that follow are not executed. 这按照我的预期记录,但后面的两个shell脚本不会执行。 Initially I thought the logs just weren't going to stdout but it turns out they're not being executed at all. 最初我认为日志不是stdout但事实证明它们根本没有被执行。 IE not removing superfluous files or pushing to a database. IE不删除多余的文件或推送到数据库。

Why are the followup shell scripts being ignored? 为什么后续shell脚本被忽略?

If you are certain your shell scripts are not running at all, and with the first code everything works - then it must be the java command deadlocks or not terminates correctly using the call() function. 如果您确定您的shell脚本根本没有运行,并且第一个代码一切正常 - 那么它必须是 java命令死锁或不使用call()函数正确终止。

You can validate that by adding a dummy file creation in your bash scripts. 您可以通过在bash脚本中添加虚拟文件来验证这一点。 Put it in the first line of the script, so if it is executed you'll get the dummy file created. 把它放在脚本的第一行,所以如果它被执行,你将获得创建的虚拟文件。 If it's not created, that means the scripts weren't executed, probably due to something with the java execution. 如果它没有创建,那意味着脚本没有被执行,可能是由于java执行的某些东西。

I would have try couple things: 我会尝试几件事:

First I would return the Popen instead of call . 首先,我会返回Popen而不是call Instead of using wait() , use communicate() : 而不是使用wait() ,使用communicate()

Interact with process: Send data to stdin. 与流程交互:将数据发送到stdin。 Read data from stdout and stderr, until end-of-file is reached. 从stdout和stderr读取数据,直到达到文件结尾。 Wait for process to terminate . 等待进程终止 communicate() returns a tuple (stdoutdata, stderrdata) . communic()返回一个元组(stdoutdata,stderrdata)

proc = subprocess.Popen(jar_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
proc.communicate()

Make sure to check both streams for data (stdout and stderr). 确保检查两个数据流(stdout和stderr)。 You might miss an error the java process raises. 您可能会错过java进程引发的错误。

Next I would try disabling the buffer by providing bufsize=0 to Popen . 接下来,我会尝试通过提供禁用缓冲bufsize=0Popen It will eliminate the option it relates to python buffering. 它将消除与python缓冲相关的选项。

If both options still don't work, try to see if there is an exception by using check_call() : 如果两个选项仍然不起作用,请尝试使用check_call()查看是否存在异常:

proc = subprocess.check_call(jar_command)

Run command with arguments. 使用参数运行命令。 Wait for command to complete. 等待命令完成。 If the return code was zero then return, otherwise raise CalledProcessError . 如果返回码为零则返回,否则引发 CalledProcessError

These options might have the answer; 这些选项可能有答案; if not, they would help the debugging process. 如果没有,他们会帮助调试过程。 Feel free to comment how this progress. 随意评论这一进展如何。

Most likely, you are forgetting that the processes streams are in fact OS-level buffers with some finite capacity. 最有可能的是,您忘记了进程流实际上是具有有限容量的OS级缓冲区。

For example, if you run a process that produces a lot of output in PIPE mode, and you wait for it to finish before trying to consume whatever that process wrote to output, you have a deadlock: 例如,如果你运行一个在PIPE模式下产生大量输出的进程,并且在尝试使用该进程写入输出的任何内容之前等待它完成,那么就会出现死锁:

  • The process has filled up the output buffer and is now blocked on writing more data to its output. 该进程已填满输出缓冲区,现在阻止将更多数据写入其输出。 Until somebody empties the buffer by reading from pipe, the process cannot continue. 在有人通过读取管道清空缓冲区之前,该过程无法继续。
  • Your program is waiting for the subprocess to finish before you read the data from its buffer. 在从缓冲区读取数据之前,您的程序正在等待子进程完成。

The correct way is to start a thread in your program that will "drain" the pipe constantly as the process is running and while your main thread is waiting. 正确的方法是在程序中启动一个线程,该线程将在进程运行时以及主线程等待时“不断”排空管道。 You must first start the process, then start the drain threads, then wait for process to finish. 您必须首先启动该过程,然后启动排水螺纹,然后等待过程完成。

For differential diagnosis, check whether the subprocess will run fine with little output (ie as long as the buffer does not fill up, such as a line or two). 对于差分诊断,检查子进程是否运行良好且输出很少(即只要缓冲区没有填满,例如一行或两行)。

The documentation for subprocess has a note about this. 子流程的文档有一个关于此的说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在 Python 中使用 subprocess.Popen() 通过 Java 程序打开文件 - Opening a File through a Java program using subprocess.Popen() in Python Python的subprocess.Popen()的Java等效项是什么? - What is the Java equivalent of Python's subprocess.Popen()? 为什么 PATH 变量不影响 Windows 中的 subprocess.Popen - Why are PATH variables not effecting subprocess.Popen in Windows 相同的cmd在shell中工作,但不在subprocess.Popen()中,用于Django下基于matlab的java程序 - The same cmd work in shell but not in subprocess.Popen() for a matlab-based java program under Django Python Subprocess.Popen 是否可以在 Electron 应用程序启动时处理/忽略 ENOENT 错误,并在命令行中继续进行而不会失败 - Could Python Subprocess.Popen handle/ignore ENOENT error on Electron app launch and proceed ahead without fail as in command line Hystrix执行模式 - Hystrix Execution Patterns 子进程python Popen打开Java jar - subprocess python Popen to open java jar Activiti-继续执行而不完成子流程 - Activiti - Continue execution without completing a subprocess Android android.util.Patterns.EMAIL_ADDRESS奇怪的行为 - Android android.util.Patterns.EMAIL_ADDRESS strange behaviour onResume() 方法中奇怪的乱序执行 - Strange Out of Order Execution in onResume() Method
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM