检测进程是否已在运行并与之协作

时间:2010-01-08 22:12:54

标签: python multiprocessing

我正在尝试创建一个程序来启动一个进程池,比如5个进程,执行一些操作,然后退出,但是让5个进程保持打开状态。之后用户可以再次运行程序,而不是启动新程序,它使用现有的5.基本上它是生产者 - 消费者模型,其中:

  1. 制片人数各不相同。
  2. 消费者数量不变。
  3. 制作人可以在不同的时间由不同的节目甚至不同的用户开始。
  4. 我正在使用内置的multiprocessing模块,目前在Python 2.6.4中,但目的是最终转移到3.1.1。

    这是一个基本的使用场景:

    1. 开始状态 - 没有进程正在运行。
    2. 用户启动program.py operation - 一个生产者,五个消费者正在运行。
    3. 操作完成 - 五名消费者正在运行。
    4. 用户启动program.py operation - 一个生产者,五个消费者正在运行。
    5. 用户启动program.py operation - 两个生产者,五个消费者正在运行。
    6. 操作完成 - 一个生产者,五个消费者正在运行。
    7. 操作完成 - 五名消费者正在运行。
    8. 用户启动program.py stop并完成 - 没有进程正在运行。
    9. 用户启动program.py start并完成 - 五个消费者正在运行。
    10. 用户启动program.py operation - 一名检察官,五名消费者正在运行。
    11. 操作完成 - 五名消费者正在运行。
    12. 用户启动program.py stop并完成 - 没有进程正在运行。
    13. 我遇到的问题是我不知道从哪里开始:

      1. 检测消费者进程是否正在运行。
      2. 从以前不相关的程序获取对它们的访问权。
      3. 以跨平台的方式做1和2。
      4. 一旦我能做到这一点,我就知​​道如何管理流程。必须有一些可靠的方法来检测现有的进程,因为我已经看到Firefox这样做是为了防止多个Firefox实例运行,但我不知道如何在Python中这样做。

3 个答案:

答案 0 :(得分:2)

有几种常见的方法来处理你的第1项(检测正在运行的进程),但是要使用它们首先需要你稍微调整你对第一次调用程序后如何启动这些后台进程的心理描述

将第一个程序看作不是启动五个进程然后退出,而是检测它是第一个启动的实例并且退出。它可以创建文件锁(防止应用程序多次出现的常用方法之一),或仅绑定到某个套接字(另一种常见方法)。这两种方法都会在第二个实例中引发异常,然后知道它不是第一个,并且可以将其注意力重新集中在联系第一个实例上。

如果您使用的是multiprocessing,则应该只需使用Manager支持,该支持涉及绑定到套接字以充当服务器。

第一个程序启动进程,创建队列,代理等等。它创建了一个允许访问它们的管理器,可能允许remote access

后续调用首先尝试在预定义套接字上联系所述服务器/管理器(或使用其他技术来发现它所在的套接字)。而不是server_forever()调用他们connect()并使用通常的multiprocessing机制进行沟通。

答案 1 :(得分:1)

看看这些不同的服务发现机制:http://en.wikipedia.org/wiki/Service_discovery

基本思想是消费者在启动时都会注册服务。生产者在开始时会经历发现过程。如果它找到了消费者,它就会与它们联系在一起。如果它没有找到它们就会启动新的消费者。在大多数所有这些系统中,服务通常也可以发布属性,因此您可以让每个消费者唯一地标识自己并向发现生产者提供其他信息。

Bonjour / zeroconf非常支持跨平台。您甚至可以将Safari配置为向您显示本地网络上的zeroconf服务,以便您可以使用它来为消费者调试服务广告。这种方法的一个优点是,您可以轻松地在不同于消费者的机器上运行生产者。

答案 2 :(得分:1)

您需要本地系统上的客户端 - 服务器模型。您可以使用TCP / IP套接字在客户端和服务器之间进行通信,但如果您不需要通过网络进行通信,则使用本地命名管道会更快。

如果我理解正确,您的基本要求是: 如果生产者已经存在,生产者应该能够产生消费者。
2.生产者应该能够与消费者沟通。
3.生产者应该能够找到已有的消费者并与他们沟通 即使生产者完成,消费者也应该继续跑步 5.不止一个生产者应该能够与消费者沟通。

让我们逐一解决这些问题:

(1)是一个简单的流程创建问题,除了消费者(子)进程应该继续运行,即使生产者(父)退出也是如此。见下文(4)。

(2)生产者可以使用named pipes与消费者沟通。请参阅os.mkfifo()man page和unix mkfifo()以创建命名管道。

(3)当您开始运行时,您需要在众所周知的路径中从使用者进程创建命名管道。生产者可以通过在同一位置查找这个众所周知的管道来查明是否有消费者在运行。如果管道不存在,则没有消费者在运行,生产者可以生成这些管道。

(4)为此,您需要使用os.setuid(),并使消费者进程像守护进程一样。请参阅setsid()的unix man page

(5)这个很棘手。多个生产者可以使用相同的命名管道与消费者进行通信,但是如果您想要可靠地识别哪个生产者发送了数据,或者您想要阻止某种交错,那么从生产者到消费者的cannot transfer more than "PIPE_BUF" amount of data来自不同生产者的数据。

更好的方法(5)是让消费者在执行时打开名为pipe的“控件”管道(/tmp/control.3456,356是消费者pid)。生产者首先使用“控制”管道建立通信渠道。当生产者连接时,它将其pid说“1234”发送给“控制”管道上的消费者,该管道告诉消费者创建一个命名管道,用于与生产者进行数据交换,比如“/tmp/data.1234”。然后生产者关闭“控制”管道,并打开“/tmp/data.1234”与消费者沟通。每个消费者都可以拥有自己的“控制”管道(使用消费者pid来区分不同消费者的管道),每个生产者获得自己的“数据”管道。当producer finishes时,它应该清理其数据管道或告诉消费者这样做。同样,当消费者完成时,它应该清理其控制管道。

这里的一个难点是防止多个生产者同时连接到单个消费者的控制管道。这里的“控制”管道是共享资源,您需要在不同的生产者之间进行同步才能访问它。使用semaphoresfile locking。请参阅 posix_ipc python模块。

注意:我已经根据一般的UNIX语义描述了上述大部分内容,但您真正需要的是能够创建守护程序进程,创建“命名”管道/队列/能够创建它们的能力,以便通过它们找到它们一个不相关的过程,以及在不相关的进程之间进行同步的能力。您可以使用任何提供此类语义的python模块。