Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Windows上无阻塞地从python子进程popen读取标准输出?_Python_Python 3.x_Subprocess - Fatal编程技术网

如何在Windows上无阻塞地从python子进程popen读取标准输出?

如何在Windows上无阻塞地从python子进程popen读取标准输出?,python,python-3.x,subprocess,Python,Python 3.x,Subprocess,我正遭受Windows Python子流程模块的困扰。 这是测试代码1(名为test1.py): 和测试代码2(名为test2.py): 通常,测试代码2生成随机整数(0~100)并无限打印出来。 我希望测试代码1创建一个子进程并启动它,实时读取标准输出(不要等待子进程完成)。 但当我运行代码时,输出是: python.exe test1.py parent process 它会永远阻塞stdout.read()。 我试过: 用communicate()替换stdout.read,不按预期工作

我正遭受Windows Python子流程模块的困扰。
这是测试代码1(名为test1.py):

和测试代码2(名为
test2.py
):

通常,测试代码2生成随机整数(0~100)并无限打印出来。 我希望测试代码1创建一个子进程并启动它,实时读取标准输出(不要等待子进程完成)。 但当我运行代码时,输出是:

python.exe test1.py
parent process
它会永远阻塞stdout.read()。 我试过:

  • 用communicate()替换stdout.read,不按预期工作,它将阻塞,直到子进程终止
  • 使用poll()方法检测子进程并读取n个字节,永远在读取时阻塞()
  • 修改test2.0代码,只生成一个number并中断循环。父进程立即打印出来(我想这是因为子进程终止了)
  • 我搜索了很多类似的答案,并按照他们的建议做了(使用标准输出而不是交流),但仍然没有成功

    有谁能帮我解释一下为什么要这么做,怎么做

    这是我的平台信息:

    win32上的Python 3.6.4(v3.6.4:d48eceb,2017年12月19日,06:54:40)[MSC v.1900 64位(AMD64)]与Python的输出缓冲有关(对于您的子进程)。尝试禁用缓冲,您的代码应该可以工作。您可以使用
    -u
    键运行python,或者调用
    sys.stdout.flush()

    要使用
    -u
    键,需要修改对
    Popen
    的调用中的参数;要使用
    flush()
    调用,需要修改
    test2.py

    另外,您的
    test1.py
    将只打印一个数字,因为您只从管道中读取1个字节,而不是在循环中读取它们

    解决方案1:

    test1.py

    import subprocess as sbp
    
    with sbp.Popen(["python3", "-u", "./test2.py"], stdout=sbp.PIPE) as proc:
        print("parent process")
        while proc.poll() is None:  # Check the the child process is still running
            data = proc.stdout.read(1)  # Note: it reads as binary, not text
            print(data)
        print("end")
    
    import subprocess as sbp
    
    with sbp.Popen("./test2.py", stdout=sbp.PIPE) as proc:
        print("parent process")
        while proc.poll() is None:  # Check the the child process is still running
            data = proc.stdout.read(1)  # Note: it reads as binary, not text
            print(data)
        print("end")
    
    import subprocess as sbp
    import sys
    
    with sbp.Popen("./test2.py", stdout=sbp.PIPE, universal_newlines=True) as proc:
        print("parent process")
        while proc.poll() is None:  # Check the the child process is still running
            data = proc.stdout.read(1)  # Note: it reads as binary, not text
            sys.stdout.write(data)
        print("end")
    
    这样,您根本不必触摸
    test2.py

    解决方案2:

    test1.py

    import subprocess as sbp
    
    with sbp.Popen(["python3", "-u", "./test2.py"], stdout=sbp.PIPE) as proc:
        print("parent process")
        while proc.poll() is None:  # Check the the child process is still running
            data = proc.stdout.read(1)  # Note: it reads as binary, not text
            print(data)
        print("end")
    
    import subprocess as sbp
    
    with sbp.Popen("./test2.py", stdout=sbp.PIPE) as proc:
        print("parent process")
        while proc.poll() is None:  # Check the the child process is still running
            data = proc.stdout.read(1)  # Note: it reads as binary, not text
            print(data)
        print("end")
    
    import subprocess as sbp
    import sys
    
    with sbp.Popen("./test2.py", stdout=sbp.PIPE, universal_newlines=True) as proc:
        print("parent process")
        while proc.poll() is None:  # Check the the child process is still running
            data = proc.stdout.read(1)  # Note: it reads as binary, not text
            sys.stdout.write(data)
        print("end")
    
    test2.py

    import random
    import time
    import sys
    
    def r():
        while True:
            yield random.randint(0, 100)
    
    for i in  r():
        print(i)
        sys.stdout.flush()  # Here you force Python to instantly flush the buffer
        time.sleep(1)
    
    这将在新行上打印每个接收到的字节,例如:

    parent process
    b'9'
    b'5'
    b'\n'
    b'2'
    b'6'
    b'\n'
    
    您可以通过在参数中提供
    编码
    或提供
    universal\u newlines=True
    将管道切换到文本模式,这将使其使用默认编码。然后直接写入父进程的
    sys.stdout
    。这基本上将子进程的输出流到父进程的输出

    test1.py

    import subprocess as sbp
    
    with sbp.Popen(["python3", "-u", "./test2.py"], stdout=sbp.PIPE) as proc:
        print("parent process")
        while proc.poll() is None:  # Check the the child process is still running
            data = proc.stdout.read(1)  # Note: it reads as binary, not text
            print(data)
        print("end")
    
    import subprocess as sbp
    
    with sbp.Popen("./test2.py", stdout=sbp.PIPE) as proc:
        print("parent process")
        while proc.poll() is None:  # Check the the child process is still running
            data = proc.stdout.read(1)  # Note: it reads as binary, not text
            print(data)
        print("end")
    
    import subprocess as sbp
    import sys
    
    with sbp.Popen("./test2.py", stdout=sbp.PIPE, universal_newlines=True) as proc:
        print("parent process")
        while proc.poll() is None:  # Check the the child process is still running
            data = proc.stdout.read(1)  # Note: it reads as binary, not text
            sys.stdout.write(data)
        print("end")
    
    这将提供输出,就像直接执行
    test2.py

    parent process
    33
    94
    27
    

    有什么理由特别需要是
    Popen
    ?为什么不使用
    子流程。检查\u输出
    ?或者,
    check\u output
    不进行实时读取吗?@NiemaMoshiri是的,
    check\u output
    类似于
    run
    ,它会一直返回,直到子进程终止。您指出关键——子进程输出缓冲!谢谢Nikita,这两种解决方案都很好。这是一个测试代码,用于在子进程和父进程之间传输数据(大数据)。所以字节格式是可以的,您在循环中使用poll()的示例也适用于我。再次感谢你!