从Python线程生成时,为什么子进程的输出会延迟?

这是我昨天发布的扩展,现在还没有解决: 为什么我的子程序的Python线程没有按预期工作?

与此同时,我发现了一些有趣的细节,所以我决定创建一个新post。 为了实现这一点:当从线程生成子进程时,存在一些问题。

平台:Windows 7企业版,Python 3.6.1

在下面的代码中,我想运行一个C-executable并将其输出到stdout成一个字符串。 出于测试目的,可执行文件接受两个参数:延迟和文件名(此处未使用)。 程序将Sleep now写入stdout ,睡眠给定的毫秒数,最后after sleepEND after sleep写入。

这是可执行文件的C源代码:

 int main(int argc, char *argv[]) { int sleep = 0; FILE * outfile = NULL; if (argc > 1) { sleep = atoi(argv[1]); } if (argc > 2) { outfile = fopen(argv[2], "w"); } printf("Sleep now...\n"); Sleep(sleep); if (outfile) fprintf(outfile, "output-1"); printf("after sleep\n"); printf("END\n"); if (outfile) fclose(outfile); fclose(stdout); exit (0); } 

这是Python代码:

 import subprocess import threading import time import os import sys def worker_nok(*args): exe, delay, filename = args proc = subprocess.Popen([exe, delay, filename], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() print("%s:" % (filename,), out) sys.stdout.flush() def worker(*args): exe, delay, filename = args flag = True proc = subprocess.Popen([exe, delay, filename], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) while flag is True: str = proc.stdout.readline() if str == b"": print("%s: got EOF" % (filename,)) flag = False else: print("%s:" % (filename,), str) print ("%s: END" % (filename,)) sys.stdout.flush() all = [] """ # 4 seconds job_thread1 = threading.Thread(target = worker, args=(["../testapp.exe", "4000", "w4sec.txt"])) job_thread1.start() all.append(job_thread1) # 8 seconds job_thread2 = threading.Thread(target = worker, args=(["../testapp.exe", "8000", "w8sec.txt"])) job_thread2.start() all.append(job_thread1) """ # 4 seconds job_thread3 = threading.Thread(target = worker_nok, args=(["../testapp.exe", "4000", "w4sec.nok"])) job_thread3.start() all.append(job_thread3) # 8 seconds job_thread3 = threading.Thread(target = worker_nok, args=(["../testapp.exe", "8000", "w8sec.nok"])) job_thread3.start() all.append(job_thread3) for t in all: t.join() 

这些工作分别有4秒,8秒和1秒的延迟。

worker_nok调用proc.communicate() – 这是我原来的方法,它不起作用:当运行这两个作业时,我得到以下输出:

 w4sec.nok: b'Sleep now...\r\nafter sleep\r\nEND\r\n' w8sec.nok: b'Sleep now...\r\nafter sleep\r\nEND\r\n' 

8秒后收到整串。 相反,我会期待

 ... 4 sec ... w4sec.nok: b'Sleep now...\r\nafter sleep\r\nEND\r\n' ... 4 sec ... w8sec.nok: b'Sleep now...\r\nafter sleep\r\nEND\r\n' 

尽管4秒的过程已经完成,但只有在第二个作业完成后才能输出。

这是我上次发帖的状态。

为了找出错误的原因,我尝试通过直接读取stdout来替换communicate() ,这是在worker函数中实现的。 当read返回空字符串时,将识别EOF条件。 在打电话时,我得到:

 ... 4 seconds ... w4sec.txt: b'Sleep now...\r\n' w4sec.txt: b'after sleep\r\n' w4sec.txt: b'END\r\n' ... 4 seconds ... w8sec.txt: b'Sleep now...\r\n' w8sec.txt: b'after sleep\r\n' w8sec.txt: b'END\r\n' w8sec.txt: got EOF w8sec.txt: END w4sec.txt: got EOF w4sec.txt: END 

不过我希望:

 w4sec.txt: b'Sleep now...\r\n' w8sec.txt: b'Sleep now...\r\n' ... 4 seconds ... w4sec.txt: b'after sleep\r\n' w4sec.txt: b'END\r\n' w4sec.txt: got EOF w4sec.txt: END ... 4 seconds ... w8sec.txt: b'after sleep\r\n' w8sec.txt: b'END\r\n' w8sec.txt: got EOF w8sec.txt: END 

最大的问题是:

1 )为什么我sleep now之前有延迟? 可执行文件可以毫不延迟地提供此输出。 stdout仅在进程终止后才可用吗?

2 )更重要的是:为什么只有在8秒呼叫结束后4秒的EOF才可用?

我希望这个输入能够清楚地说明为什么原始版本显示了观察到的行为: stdout处于EOF条件太晚了,并且留下了通信()阻塞的调用!

我感谢任何投入,因为我已经工作了超过12个小时……