【问题标题】:Process getting stuck after being launched from another process从另一个进程启动后进程卡住
【发布时间】:2021-11-07 13:11:59
【问题描述】:

我正在使用 Dash 开发一种特定类型的应用程序,它需要通过按下按钮执行的操作在单独的进程中执行。反过来,这个过程是可并行的,并且在某些情况下会产生子进程以进行高效计算。在这种情况下给出的配置会使子进程卡住。下面的代码重现了如下描述的情况:

import multiprocessing
import time
import dash
from dash import html
from dash.dependencies import Input, Output

app = dash.Dash(__name__)

app.layout = html.Div([
    html.Button(id='refresh-button', children='Button'),
    html.Div(id='dynamic-container1')
])


def run_function(i):
    print('hello')
    time.sleep(15)
    print(f'hello world {i}')


def run_process():
    num = 1
    print('hello world 00000')
    process = multiprocessing.Process(target=run_function, args=(num,))
    process.start()
    process.join()
    print('hello world')


@app.callback(Output('dynamic-container1', 'children'), Input('refresh-button', 'n_clicks'))
def refresh_state(click):
    if click == 0 or click is None:
        return None
    p = multiprocessing.Process(target=run_process)
    p.start()
    p.join()

    return None

if __name__ == '__main__':
    app.run_server(debug=True)

按下按钮时此应用程序的输出始终如下:

Connected to pydev debugger (build 172.3968.37)
Dash is running on http://127.0.0.1:8050/

 * Serving Flask app 'main' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
pydev debugger: process 6884 is connecting

hello world 00000

这意味着使用函数run_process()的第一个进程已经启动,但是子进程run_function(i)甚至没有启动。我试图在有关 Python 中的多处理的流行书籍中找到解释以及对这些“链接”过程的任何指导,但无济于事。据我了解,新的子进程run_function(i)应该占用一个单独的核心(如果有空闲核心),而不是依赖父进程run_process()消耗的资源。请你给我解释一下这个机制?我怀疑在这段代码中run_function(i) 可能会被强制消耗与run_process() 相同的资源,所以系统基本上只是限制任何新进程从相同的资源开始,但我想从更多的 Python 专家用户。 我在 Win7 上使用 Python 3.7 和 Pycharm Community 2017.2.3 重现了这个例子

【问题讨论】:

    标签: python python-multiprocessing plotly-dash


    【解决方案1】:

    我无法重现您的错误,我认为这是因为您使用的是 Windows(我在 Linux 上使用 python 3.9),所以我无法为您找到错误,但也许我可以给您一些提示:

    第一:要找到错误,请尝试将代码简化为问题的核心(您可以删除整个破折号以检查是否是错误)。在我的测试中,无论有没有破折号,结果都是一样的

    第二: Windows 和 Linux 处理多处理的东西有点不同: windows 生成进程:

    父进程启动一个新的 python 解释器进程。子进程只会继承运行进程对象的 run() 方法所需的资源。特别是,不会继承父进程中不必要的文件描述符和句柄。与使用 fork 或 forkserver 相比,使用这种方法启动进程相当慢。

    Unix 系统 fork 进程

    父进程使用 os.fork() 来分叉 Python 解释器。子进程在开始时实际上与父进程相同。父进程的所有资源都由子进程继承。请注意,安全地分叉多线程进程是有问题的。

    使用 Unix 系统,您可以生成 (multiprocessing.set_start_method("spawn")),这样我无法重现您的错误,但是通过这个 fork/spawn 示例,我想明确指出,有时会出现问题即使使用相同的软件包,Windows 和 linux 之间也会有所不同。我认为您对多处理的理解是正确的。 (也许this site 也有帮助。)

    第三:文档中有一些programming guidelines 你应该知道。也许他们也会有所帮助。一般来说,multiprocessing 包不能很好地与许多交互式 python shell(如 IDLE 或 pycharm)一起使用,这在较新的版本上可能会更好。也许你应该从终端尝试一下,看看这是否改变了什么。

    我希望这会有所帮助。

    【讨论】:

    • 当您在 Windows 上时,您的 run_process 函数正在生成一个新进程,该进程将执行您的函数 run_function(),但是当该函数打印时,在父进程标准 IO 控制台中不可见,即这就是为什么它似乎“卡住”了,但我不确定为什么它在 run_process 中完成最终打印后没有打印。
    • 我从 Windows 命令提示符运行了您的示例,打印语句的流程正如预期的那样运行良好。因此,您的情况可能是由于 pycharm 无法收集子进程的 I/O 的方式。
    • 是的,可能是因为 Pycharm 中的这个issue
    猜你喜欢
    • 2012-05-12
    • 2015-03-22
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-14
    相关资源
    最近更新 更多