【问题标题】:Can I pass a file to Popen and still have it run asynchronously我可以将文件传递给 Popen 并且仍然让它异步运行吗
【发布时间】:2016-10-03 21:12:24
【问题描述】:

我有一个基于 Django 的服务器,我正在调用一个执行大量工作的脚本。这需要是异步的,所以我使用 Popen。但是,为了调试,我想将 stdout 和 stderr 从 PIPE 重定向到文件。这会影响异步性能吗?

当python脚本本身已经完成(并且已经进行了返回调用)时,我应该如何确保文件正确打开和关闭。

【问题讨论】:

    标签: python asynchronous subprocess


    【解决方案1】:

    Popen 默认异步运行。

    Popen 对象可以在以后存储和查询。

    p = subproccess.Popen(executable)
    
    # continue with other work
    
    p.poll() # returns None if p is still running, returncode otherwise
    p.terminate() # closes the process forcefully
    
    p.wait() # freezes the execution until process finishes - makes it synchronous
    

    只需将p 存储在某处,直到必须检查其状态,例如如果没有更好的地方,则在已启动进程的全局列表中。

    更新

    问题似乎是如何打开文件,将其提供给Popen,然后在进程完成后关闭文件,而不保留任何引用。

    这可以简单地用一个线程来完成:

    def run_process(executable, filename):
        with open(filename, 'w') as f:
            subprocess.Popen(executable, stdout=f).wait()
    
    Thread(target=run_process, args=(executable, filename)).start()
    

    运行它并忘记它。 run_process 将冻结直到进程完成,然后它将关闭文件,但这一切都发生在不同的线程中。

    注意:如果在 django 进程完成时线程或进程没有完成,您可能关心也可能不关心它们会发生什么。

    为了处理这个问题,你可能会创建一个更复杂的线程,在 django 退出之前你会记住并停止它;它也可能关闭进程或等待它完成......

    【讨论】:

    • 我知道它默认运行异步,我的意思是,如果我执行 stdout=f 其中 f 是 python 文件对象,如果 python 在子进程仍在运行时离开文件的参考框架会发生什么?
    • @DylanLawrence 啊!该文件将保持打开状态,直到您关闭它(但不要使用with open(...))。另一方面,您应该保留文件引用,以便稍后关闭它。
    • 所以一个问题是,这是一个面向 Web 的应用程序,所以这个脚本正在处理客户端,而子进程调用基本上是“一劳永逸”。如果我不保留变量,操作系统会处理清理吗?
    • 太好了,谢谢。我需要关心线程会发生什么吗?如果我不在代码中做任何特别的事情,它只会自行清理,对吗?
    • @DylanLawrence 如果线程的daemon 标志是False(默认值),则在所有这些线程完成之前,主线程不会退出。这可能正是你想要的,我不知道。
    【解决方案2】:

    这取决于您的程序需要的异步程度。对标准输出的写入会进入操作系统的文件缓存,这通常很快,但在数据刷新到磁盘时可能会不时等待。通常这不是问题。

    由于 stdout 不是控制台,它会进行缓冲写入,如果程序遇到跳过刷新管道的非标准错误,这可能会成为问题。缓冲还可以延迟文件中的内容,例如,处理文件的外部程序可能不会立即看到日志。

    父进程应在启动子进程后关闭文件视图,操作系统将在进程终止时关闭文件。

    with open('stdout', 'w') as out, open('stderr', 'w') as err:
        proc = subprocess.Popen(['myprog'], stdout=out, stderr=err)
    

    【讨论】:

    • 好的,所以使用with 根本不会阻止python脚本的执行?
    • 父脚本?不,它全速运行。您在启动时将文件句柄传递给了子级,而父级现在完全脱离了循环。子写入直接进入操作系统的文件缓存。
    • @tdelaney 在with 块末尾调用的file.close() 不应该影响文件吗?
    • @zvone - 不,它会在父级中关闭文件,但在子级中保持打开状态。
    • @tdelaney 很好。在那种情况下,这比我的解决方案要好;)
    猜你喜欢
    • 1970-01-01
    • 2016-08-22
    • 1970-01-01
    • 2018-06-04
    • 2021-12-09
    • 2018-04-08
    • 1970-01-01
    • 2015-08-19
    • 2022-01-19
    相关资源
    最近更新 更多