Python调用Maven执行Java代码时,输出重定向后顺序错乱原因
终端输出重定向后Python打印与Maven输出顺序颠倒的原因分析
你用Python调用Maven命令执行Java代码的逻辑是这样的:
with changeDir(runDir): print "mvn clean" subprocess.call(["mvn clean"], shell=True) with changeDir(runDir): print "mvn compile" subprocess.call(["mvn compile"], shell=True) print "compile time",datetime.now() - startTime with changeDir(runDir): print "mvn package" subprocess.call(["mvn package -DskipTests=true"], shell=True) with changeDir(runDir): subprocess.call(["export MAVEN_OPTS=\"-Xmx10g -Xms10g -XX:MaxPermSize=10g -XX:+UseConcMarkSweepGC -XX:-UseGCOverheadLimit\""], shell=True) print "mvn exec" subprocess.call(["mvn exec:java -Dexec.mainClass=examples.Example -Dexec.args=\"pathToFile"+fname+\"\""], shell=True)
你发现一个奇怪的现象:直接在终端输出时,Python的提示信息(比如mvn clean)和Maven的执行输出是按代码顺序依次显示的,但把终端输出重定向到out.txt后,所有Maven的Java相关输出会先堆在文件前面,之后才会出现Python的打印内容。
这其实是标准输出(stdout)的缓冲机制在捣鬼!具体原因是:
- Python的
print函数默认是行缓冲模式:在终端输出时,每打印一行就会立刻刷新到屏幕上;但当输出被重定向到文件时,Python会自动切换成全缓冲模式——也就是要攒够一定量的数据(通常是4KB或8KB)才会一次性写入文件,不会实时刷新。 - 而你通过
subprocess.call调用的Maven命令,它的输出缓冲策略和Python不一样。Maven本身的输出在重定向时,要么是直接无缓冲输出,要么缓冲阈值更低,所以它的内容会第一时间被写入文件。 - 等到整个Python程序运行结束,Python才会把之前缓冲的所有
print内容一次性dump到文件里,这就造成了我们看到的顺序颠倒问题。
如果想要解决这个问题,你可以试试这几种方法:
- 在每个
print语句后手动添加刷新操作:先导入sys模块,然后在print后加sys.stdout.flush(); - 启动Python脚本时加上
-u参数,强制标准输出使用无缓冲模式; - 把
print替换成直接写入标准输出并刷新的写法,比如sys.stdout.write("mvn clean\n"); sys.stdout.flush()。
内容的提问来源于stack exchange,提问作者april
相关产品推荐
相关产品推荐

