在Python中分叉时,父进程和子进程之间的通信进程

时间:2018-02-07 20:03:40

标签: python fork ipc

我试图让一个Python程序同时运行一个处理循环,并使用对os.fork()的调用来获得结果的广播服务,比如

pid = os.fork()
if pid == 0:
    time.sleep(3)
    keep_updating_some_value_while_parent_is_running()
else:
    broadcast_value()

这里由子进程执行的keep_updating_some_value_while_parent_is_running()存储一些值,只要父进程正在运行,它就会不断更新。它实际上将值写入磁盘,以便父级可以轻松访问它。它通过检查父运行的Web服务是否可用来检测父运行。

broadcast_value()运行一个Web服务,在咨询时它从磁盘读取最新值并提供服务。

这种实施方式效果很好,但由于以下几个原因而不能令人满意:

  1. time.sleep(3)是必需的,因为Web服务需要 一些启动时间。完全无法保证在3秒内服务将启动并运行,而另一方面它可能要早得多。

  2. 通过磁盘共享数据并不总是一个好的选择,甚至不可能(因此这个解决方案不能很好地概括)。

  3. 通过检查Web服务是否可用来检测父服务器是否正常运行并不是最理想的,而且对于不同类型的进程(无法自动轮询),这根本不起作用。此外,可能是Web服务运行正常,但存在临时可用性问题。

  4. 该解决方案取决于操作系统。

  5. 当孩子出于某种原因失败或退出时,父母会保留 跑步(这可能是所希望的行为,但并非总是如此)。

  6. 我想要的是让子进程了解父进程何时启动和运行,何时停止,以及父进程获取子请求时计算的最新值的方法,最好是独立于OS的方式。涉及非标准库的解决方案也是受欢迎的。

1 个答案:

答案 0 :(得分:2)

我建议使用multiprocessing而不是os.fork(),因为它会为您处理很多细节。特别是它提供了Manager类,它提供了一种在进程之间共享数据的好方法。您将启动一个Process来处理数据,另一个用于执行Web服务,并将它们传递给Manager提供的共享数据字典。然后主要过程负责设置所有这些(并等待过程完成 - 否则Manager中断。)

这可能是这样的:

import time
from multiprocessing import Manager, Process

def get_data():
    """ Does the actual work of getting the updating value. """

def update_the_data(shared_dict):
    while not shared_dict.get('server_started'):
        time.sleep(.1)
    while True:
        shared_dict['data'] = get_data()
        shared_dict['data_timestamp'] = time.time()
        time.sleep(LOOP_DELAY)


def serve_the_data(shared_dict):
    server = initialize_server() # whatever this looks like
    shared_dict['server_started'] = True
    while True:
        server.serve_with_timeout()
        if time.time() - shared_dict['data_timestamp'] > 30:
            # child hasn't updated data for 30 seconds; problem?
            handle_child_problem()


if __name__ == '__main__':
    manager = Manager()
    shared_dict = manager.dict()
    processes = [Process(target=update_the_data, args=(shared_dict,)),
        Process(target=serve_the_data, args=(shared_dict,))]
    for process in processes:
        process.start()
    for process in processes:
        process.join()