如何列出多处理池启动的进程?

时间:2014-06-05 19:31:51

标签: python multiprocessing

尝试在multiprocessing list-variable'poolList`中存储multiprocessing进程实例时,我收到以下异常:

SimpleQueue objects should only be shared between processes through inheritance

我想将PROCESS实例存储在变量中的原因是为了能够稍后终止所有或仅仅其中一些(例如,如果一个进程冻结)。如果在变量中存储PROCESS不是一个选项,我想知道如何获取或列出由mutliprocessing POOL启动的所有PROCESSES。这与.current_process()方法的作用非常相似。除了.current_process只需要一个进程,而我需要启动所有进程或当前正在运行的所有进程。

两个问题:

  1. 甚至可以存储流程的实例(由于mp.current_process()

  2. 目前我只能从流程运行的函数内部获取单个进程(使用myFunct()方法从.current_process()内部)。

  3. 相反,我想列出multiprocessing当前运行的所有进程。如何实现呢?


    import multiprocessing as mp
    
    poolList=mp.Manager().list()
    
    def myFunct(arg):
        print 'myFunct(): current process:', mp.current_process()
    
        try: poolList.append(mp.current_process())
        except Exception, e: print e
    
        for i in range(110):
            for n in range(500000):
                pass
            poolDict[arg]=i
        print 'myFunct(): completed', arg, poolDict
    
    from multiprocessing import Pool
    pool = Pool(processes=2)
    myArgsList=['arg1','arg2','arg3']
    
    pool=Pool(processes=2)
    pool.map_async(myFunct, myArgsList)
    pool.close()
    pool.join()
    

3 个答案:

答案 0 :(得分:5)

列出由Pool() - 实例启动的进程(如果我理解正确的话,这就是你的意思),有pool._pool-list。它包含流程的实例。

但是,它不是文档化界面的一部分,因此,实际上不应该使用它。 但是......似乎有点不太可能会像那样改变。我的意思是,他们是否应该停止在池中有一个内部进程列表?而不是叫那个_pool? 而且,令我很生气的是,至少不是一个获取流程的方法。或者其他的东西。 并且由于某些名称更改而导致的处理不应该那么困难。

但是,使用风险依然存在:

from multiprocessing import pool

# Have to run in main
if __name__ == '__main__':
    # Create 3 worker processes
    _my_pool = pool.Pool(3)

    # Loop, terminate, and remove from the process list
    # Use a copy [:] of the list to remove items correctly
    for _curr_process in _my_pool._pool[:]:
        print("Terminating process "+ str(_curr_process.pid))
        _curr_process.terminate()
        _my_pool._pool.remove(_curr_process)

    # If you call _repopulate, the pool will again contain 3 worker processes.
    _my_pool._repopulate_pool()
    for _curr_process in _my_pool._pool[:]:
        print("After repopulation "+ str(_curr_process.pid))

该示例创建一个池并手动终止所有进程。

重要的是,您要记得自己删除从池中终止的进程,我希望Pool()继续照常工作。

_my_pool._repopulate再次将工作进程数增加到3,不需要回答问题,但会给出一些幕后洞察力。

答案 1 :(得分:2)

  1. 您正在创建托管List对象,但随后让关联的Manager对象过期。

  2. Process个对象是可共享的,因为它们不会被发现;也就是说,它们并不简单。

  3. 奇怪的是,multiprocessing模块没有等同于threading.enumerate() - 也就是说,无法列出所有未完成的流程。作为一种解决方法,我只是将procs存储在列表中。我从不terminate()进程,而是在父进程sys.exit(0)。这很粗糙,因为工人会把事情处于不一致的状态,但是对于较小的程序来说这是可以的

  4. 为了杀死冷冻工人,我建议:1)工人接受心跳"心跳"队列中的作业偶尔出现,2)如果父母通知工作人员A在一定时间内没有响应心跳,则p.terminate()。考虑在另一个SO问题中重述问题,因为它很有趣。

  5. 老实说,map的东西比使用管理器容易得多。

    这是我使用过的经理示例。工作人员将内容添加到共享列表中。另一名工人偶尔会醒来,处理清单上的所有内容,然后再回到睡眠状态。该代码还具有详细日志,这对于简化调试至关重要。

    # producer adds to fixed-sized list; scanner uses them
    
    import logging, multiprocessing, sys, time
    
    
    def producer(objlist):
        '''
        add an item to list every sec; ensure fixed size list
        '''
        logger = multiprocessing.get_logger()
        logger.info('start')
        while True:
            try:
                time.sleep(1)
            except KeyboardInterrupt:
                return
            msg = 'ding: {:04d}'.format(int(time.time()) % 10000)
            logger.info('put: %s', msg)
            del objlist[0]
            objlist.append( msg )
    
    
    def scanner(objlist):
        '''
        every now and then, run calculation on objlist
        '''
        logger = multiprocessing.get_logger()
        logger.info('start')
        while True:
            try:
                time.sleep(5)
            except KeyboardInterrupt:
                return
            logger.info('items: %s', list(objlist))
    
    
    def main():
        logger = multiprocessing.log_to_stderr(
                level=logging.INFO
        )
        logger.info('setup')
    
        # create fixed-length list, shared between producer & consumer
        manager = multiprocessing.Manager()
        my_objlist = manager.list( # pylint: disable=E1101
            [None] * 10
        )
    
        multiprocessing.Process(
            target=producer,
            args=(my_objlist,),
            name='producer',
        ).start()
    
        multiprocessing.Process(
            target=scanner,
            args=(my_objlist,),
            name='scanner',
            ).start()
    
        logger.info('running forever')
        try:
            manager.join() # wait until both workers die
        except KeyboardInterrupt:
            pass
        logger.info('done')
    
    
    if __name__=='__main__':
        main()
    

答案 2 :(得分:1)

是的,您可以获取所有活动的进程并根据进程名称执行操作 例如

multiprocessing.Process(target=foo, name="refresh-reports")

然后

for p in multiprocessing.active_children():
   if p.name == "foo":
      p.terminate()