免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 30536 | 回复: 12
打印 上一主题 下一主题

multiprocessing.Process 产生的子进程如何正常退出? [复制链接]

论坛徽章:
60
20周年集字徽章-20	
日期:2020-10-28 14:04:3015-16赛季CBA联赛之北京
日期:2016-07-06 15:42:0715-16赛季CBA联赛之同曦
日期:2016-06-12 10:38:0915-16赛季CBA联赛之佛山
日期:2016-05-27 11:54:56黄金圣斗士
日期:2015-12-02 11:44:35白银圣斗士
日期:2015-11-25 14:32:43白银圣斗士
日期:2015-11-23 12:53:352015亚冠之布里斯班狮吼
日期:2015-10-21 16:55:482015亚冠之首尔
日期:2015-09-01 16:46:052015亚冠之德黑兰石油
日期:2015-08-31 11:39:192015亚冠之萨济拖拉机
日期:2015-08-28 21:06:5315-16赛季CBA联赛之广东
日期:2016-07-12 14:58:53
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-03-29 00:21 |只看该作者 |倒序浏览

下面是一段示意代码 ttt.py:
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-

  3. import multiprocessing
  4. import time
  5. import os

  6. class test(multiprocessing.Process):
  7.         def run(self):
  8.                 print 'sub process [ppid]: %d,[pid]: %d -- sleep 5 --' %(os.getppid(),os.getpid())
  9.                 time.sleep(5)
  10.                 print 'sub process [ppid]: %d,[pid]: %d -- done --' % (os.getppid(),os.getpid())

  11. b = 0
  12. while True:
  13.         print '-- [pid]: %d main process starting --' %os.getpid()
  14.         while b < 10 :
  15.                 p = test()
  16.                 p.start()
  17.                 b +=1
  18.         print '-- [pid]: %d main process sleep 10 --' %os.getpid()
  19.         time.sleep(100)
复制代码
运行后:
  1. [root@localhost pytest]# python ttt.py
  2. -- [pid]: 23695 main process starting --
  3. sub process [ppid]: 23695,[pid]: 23696 -- sleep 5 --
  4. sub process [ppid]: 23695,[pid]: 23697 -- sleep 5 --
  5. sub process [ppid]: 23695,[pid]: 23698 -- sleep 5 --
  6. sub process [ppid]: 23695,[pid]: 23699 -- sleep 5 --
  7. sub process [ppid]: 23695,[pid]: 23700 -- sleep 5 --
  8. sub process [ppid]: 23695,[pid]: 23702 -- sleep 5 --
  9. sub process [ppid]: 23695,[pid]: 23701 -- sleep 5 --
  10. sub process [ppid]: 23695,[pid]: 23703 -- sleep 5 --
  11. sub process [ppid]: 23695,[pid]: 23704 -- sleep 5 --
  12. -- [pid]: 23695 main process sleep 10 --
  13. sub process [ppid]: 23695,[pid]: 23705 -- sleep 5 --
  14. sub process [ppid]: 23695,[pid]: 23697 -- done --
  15. sub process [ppid]: 23695,[pid]: 23696 -- done --
  16. sub process [ppid]: 23695,[pid]: 23698 -- done --
  17. sub process [ppid]: 23695,[pid]: 23699 -- done --
  18. sub process [ppid]: 23695,[pid]: 23700 -- done --
  19. sub process [ppid]: 23695,[pid]: 23701 -- done --
  20. sub process [ppid]: 23695,[pid]: 23704 -- done --
  21. sub process [ppid]: 23695,[pid]: 23703 -- done --
  22. sub process [ppid]: 23695,[pid]: 23702 -- done --
  23. sub process [ppid]: 23695,[pid]: 23705 -- done --
复制代码
产生了10个子进程,完成之后 ,我 ps -ef | grep python, 得到:
  1. [root@localhost ~]# ps -ef | grep [p]ython
  2. root     23695  8791  0 00:19 pts/4    00:00:00 python ttt.py
  3. root     23696 23695  0 00:19 pts/4    00:00:00 [python] <defunct>
  4. root     23697 23695  0 00:19 pts/4    00:00:00 [python] <defunct>
  5. root     23698 23695  0 00:19 pts/4    00:00:00 [python] <defunct>
  6. root     23699 23695  0 00:19 pts/4    00:00:00 [python] <defunct>
  7. root     23700 23695  0 00:19 pts/4    00:00:00 [python] <defunct>
  8. root     23701 23695  0 00:19 pts/4    00:00:00 [python] <defunct>
  9. root     23702 23695  0 00:19 pts/4    00:00:00 [python] <defunct>
  10. root     23703 23695  0 00:19 pts/4    00:00:00 [python] <defunct>
  11. root     23704 23695  0 00:19 pts/4    00:00:00 [python] <defunct>
  12. root     23705 23695  0 00:19 pts/4    00:00:00 [python] <defunct>
  13. [root@localhost ~]#
复制代码
子进程都是僵尸进程,怎么会这样呢? 如何正确退出子进程? python 新手,求解答!








论坛徽章:
13
双鱼座
日期:2013-10-23 09:30:05数据库技术版块每日发帖之星
日期:2016-04-20 06:20:00程序设计版块每日发帖之星
日期:2016-03-09 06:20:002015亚冠之塔什干火车头
日期:2015-11-02 10:07:452015亚冠之德黑兰石油
日期:2015-08-30 10:07:07数据库技术版块每日发帖之星
日期:2015-08-28 06:20:00数据库技术版块每日发帖之星
日期:2015-08-05 06:20:002015年迎新春徽章
日期:2015-03-04 09:57:09辰龙
日期:2014-12-03 14:45:52酉鸡
日期:2014-07-23 09:46:23亥猪
日期:2014-03-13 08:46:22金牛座
日期:2014-02-11 09:36:21
2 [报告]
发表于 2014-03-29 10:23 |只看该作者
#!/usr/bin/python
# -*- coding: utf-8 -*-

import multiprocessing
import time
import os

class test(multiprocessing.Process):
        def run(self):
                print 'sub process [ppid]: %d,[pid]: %d -- sleep 5 --' %(os.getppid(),os.getpid())
                time.sleep(5)
                print 'sub process [ppid]: %d,[pid]: %d -- done --' % (os.getppid(),os.getpid())

b = 0
while True:
        print '-- [pid]: %d main process starting --' %os.getpid()
        p={}
        for i in range(10) :
            p[i] = test()
            p[i].start()
            p[i].join()
        print '-- [pid]: %d main process sleep 10 --' %os.getpid()
        time.sleep(100)

论坛徽章:
11
技术图书徽章
日期:2014-03-01 14:44:34天蝎座
日期:2014-05-21 22:11:59金牛座
日期:2014-05-30 17:06:14
3 [报告]
发表于 2014-03-29 11:08 |只看该作者
start()
Start the process’s activity.

This must be called at most once per process object. It arranges for the object’s run() method to be invoked in a separate process.

join([timeout])
If the optional argument timeout is None (the default), the method blocks until the process whose join() method is called terminates. If timeout is a positive number, it blocks at most timeout seconds.

A process can be joined many times.

A process cannot join itself because this would cause a deadlock. It is an error to attempt to join a process before it has been started.


看文档,start下面就是join,回收子进程,和C系统调用wait/waitpid功能类似。

论坛徽章:
60
20周年集字徽章-20	
日期:2020-10-28 14:04:3015-16赛季CBA联赛之北京
日期:2016-07-06 15:42:0715-16赛季CBA联赛之同曦
日期:2016-06-12 10:38:0915-16赛季CBA联赛之佛山
日期:2016-05-27 11:54:56黄金圣斗士
日期:2015-12-02 11:44:35白银圣斗士
日期:2015-11-25 14:32:43白银圣斗士
日期:2015-11-23 12:53:352015亚冠之布里斯班狮吼
日期:2015-10-21 16:55:482015亚冠之首尔
日期:2015-09-01 16:46:052015亚冠之德黑兰石油
日期:2015-08-31 11:39:192015亚冠之萨济拖拉机
日期:2015-08-28 21:06:5315-16赛季CBA联赛之广东
日期:2016-07-12 14:58:53
4 [报告]
发表于 2014-03-29 19:13 |只看该作者
回复 2# bikong0411


    这样的话是执行完一个,退出一个。 有没有办法,同时运行 10 个子进程呢 ?

论坛徽章:
60
20周年集字徽章-20	
日期:2020-10-28 14:04:3015-16赛季CBA联赛之北京
日期:2016-07-06 15:42:0715-16赛季CBA联赛之同曦
日期:2016-06-12 10:38:0915-16赛季CBA联赛之佛山
日期:2016-05-27 11:54:56黄金圣斗士
日期:2015-12-02 11:44:35白银圣斗士
日期:2015-11-25 14:32:43白银圣斗士
日期:2015-11-23 12:53:352015亚冠之布里斯班狮吼
日期:2015-10-21 16:55:482015亚冠之首尔
日期:2015-09-01 16:46:052015亚冠之德黑兰石油
日期:2015-08-31 11:39:192015亚冠之萨济拖拉机
日期:2015-08-28 21:06:5315-16赛季CBA联赛之广东
日期:2016-07-12 14:58:53
5 [报告]
发表于 2014-03-29 19:36 |只看该作者
回复 3# timespace


    我的意图是:

while Ture:
   data = "从数据库里获取数据"
   for i in data:
        #然后
        p = class(i)
        p.start()
        p.join() 如果这里使用了这个,就停在这里了,得for循环里的子进程全部完成后while循环才能继续走。 我是希望产生子进程后,子进程在运行,但又不影响while循环继续。

但是这里不使用join。 子进程结束后就变成僵尸进程了,如我主题所述。

不知道咋搞了,能指点一二么?


论坛徽章:
60
20周年集字徽章-20	
日期:2020-10-28 14:04:3015-16赛季CBA联赛之北京
日期:2016-07-06 15:42:0715-16赛季CBA联赛之同曦
日期:2016-06-12 10:38:0915-16赛季CBA联赛之佛山
日期:2016-05-27 11:54:56黄金圣斗士
日期:2015-12-02 11:44:35白银圣斗士
日期:2015-11-25 14:32:43白银圣斗士
日期:2015-11-23 12:53:352015亚冠之布里斯班狮吼
日期:2015-10-21 16:55:482015亚冠之首尔
日期:2015-09-01 16:46:052015亚冠之德黑兰石油
日期:2015-08-31 11:39:192015亚冠之萨济拖拉机
日期:2015-08-28 21:06:5315-16赛季CBA联赛之广东
日期:2016-07-12 14:58:53
6 [报告]
发表于 2014-03-29 20:26 |只看该作者
其实,我的需求是:

1.  不断从数据库获取数据,一次性可能是获取5条数据
2. 每条数据相当于一个任务,一个任务产生一个子进程去处理它,获取的任务立即执行,如立即执行5个任务
3. 主程序不等待任务(子进程)执行完,继续从数据库中获取数据(任务),如果获取到了,又立刻执行,如此反复

PS: 无需担心有多少条数据(任务)在运行!

---------------

但是,之前主程序衍生出的子进程,我现在不知道如何正确退出,不正确退出,就会变成僵尸进程了。

比如,以下的一个例子:
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-

  3. import multiprocessing
  4. import time
  5. import os

  6. class test(multiprocessing.Process):
  7.         def run(self):
  8.                 print 'sub process [ppid]: %d,[pid]: %d -- sleep 5 --' %(os.getppid(),os.getpid())
  9.                 time.sleep(5)
  10.                 print 'sub process [ppid]: %d,[pid]: %d -- done --' % (os.getppid(),os.getpid())

  11. while True:
  12.         i = 0
  13.         p = {}
  14.         print '-- [pid]: %d main process starting --' %os.getpid()
  15.         while i < 10 :
  16.                 p[i] = test()
  17.                 p[i].start()
  18.                 i+=1
  19.         print '-- [pid]: %d main process sleep 100 --' %os.getpid()
  20.         #sleep 100
  21.         time.sleep(100)
复制代码
我执行后,是可以立即执行10个子进程的,而主进程会等待 100 秒 ,5秒钟后子进程都执行完了 ,主进程还在 sleep .
此时,我去 ps -ef 查询的时候,这些子进程就变成了僵尸进程拉。因为我没有正确退出子进程。
  1. [root@localhost ~]# ps -ef | grep [p]ython
  2. root      1406 14991  0 20:24 pts/1    00:00:00 python ttt.py
  3. root      1407  1406  0 20:24 pts/1    00:00:00 [python] <defunct>
  4. root      1408  1406  0 20:24 pts/1    00:00:00 [python] <defunct>
  5. root      1409  1406  0 20:24 pts/1    00:00:00 [python] <defunct>
  6. root      1410  1406  0 20:24 pts/1    00:00:00 [python] <defunct>
  7. root      1411  1406  0 20:24 pts/1    00:00:00 [python] <defunct>
  8. root      1412  1406  0 20:24 pts/1    00:00:00 [python] <defunct>
  9. root      1413  1406  0 20:24 pts/1    00:00:00 [python] <defunct>
  10. root      1414  1406  0 20:24 pts/1    00:00:00 [python] <defunct>
  11. root      1415  1406  0 20:24 pts/1    00:00:00 [python] <defunct>
  12. root      1416  1406  0 20:24 pts/1    00:00:00 [python] <defunct>
  13. [root@localhost ~]#
复制代码
两位大神, 我这个需求如何去做呢? 求指点! @bikong0411 @timespace

论坛徽章:
11
技术图书徽章
日期:2014-03-01 14:44:34天蝎座
日期:2014-05-21 22:11:59金牛座
日期:2014-05-30 17:06:14
7 [报告]
发表于 2014-03-29 21:17 |只看该作者
回复 6# reyleon
这种需求用进程池或线程池更简单http://docs.python.org/2.7/library/multiprocessing.html#module-multiprocessing.pool,无需关心进程管理的问题。


   

论坛徽章:
60
20周年集字徽章-20	
日期:2020-10-28 14:04:3015-16赛季CBA联赛之北京
日期:2016-07-06 15:42:0715-16赛季CBA联赛之同曦
日期:2016-06-12 10:38:0915-16赛季CBA联赛之佛山
日期:2016-05-27 11:54:56黄金圣斗士
日期:2015-12-02 11:44:35白银圣斗士
日期:2015-11-25 14:32:43白银圣斗士
日期:2015-11-23 12:53:352015亚冠之布里斯班狮吼
日期:2015-10-21 16:55:482015亚冠之首尔
日期:2015-09-01 16:46:052015亚冠之德黑兰石油
日期:2015-08-31 11:39:192015亚冠之萨济拖拉机
日期:2015-08-28 21:06:5315-16赛季CBA联赛之广东
日期:2016-07-12 14:58:53
8 [报告]
发表于 2014-03-29 22:19 |只看该作者
回复 7# timespace


主程序不等待任务(子进程)执行完,继续从数据库中获取数据(任务)!    能否帮我写个简单的示例?

论坛徽章:
11
技术图书徽章
日期:2014-03-01 14:44:34天蝎座
日期:2014-05-21 22:11:59金牛座
日期:2014-05-30 17:06:14
9 [报告]
发表于 2014-03-30 13:42 |只看该作者
回复 8# reyleon
如果你很确定,每条数据新建一个进程没有问题,比如进程数限制或服务器负载,那么也有一种办法。
基本思路:
1. 主进程管理子进程的创建和销毁
2. proxy进程负责数据IO操作
3. worker进程处理具体数据

下面是一个可正常运行的框架:
  1. # -*- coding: utf-8 -*-
  2. import multiprocessing as mp
  3. import os
  4. import random
  5. from signal import signal, SIGINT, SIG_IGN, siginterrupt
  6. import time

  7. def data_source():
  8.     """数据源。

  9.     随机选择一个浮点数,作为worker进程的sleep时间,
  10.     具体实践时可以将这部分实现改为读取数据库。
  11.     """
  12.     dataset = [0.1, 0.2, 0.3, 0.4, 0.5]
  13.     while True:
  14.         time.sleep(0.2)
  15.         yield random.choice(dataset)

  16. def proc_proxy(cntl_q, data_q, exit_flag):
  17.     """从数据源读取数据。

  18.     先通过cntl_q通知主进程,
  19.     再将数据通过data_q发给worker。
  20.     """
  21.     for item in data_source():
  22.         cntl_q.put({'event': 'data'})
  23.         data_q.put(item)
  24.         if exit_flag.is_set():
  25.             cntl_q.put({'event': 'exit', 'pid': os.getpid()})
  26.             break


  27. def proc_worker(cntl_q, data_q):
  28.     """处理数据。

  29.     从data_q获取数据,处理完毕后通过cntl_q通知主进程,
  30.     然后退出。
  31.     """
  32.     item = data_q.get()
  33.     time.sleep(item)
  34.     cntl_q.put({'event': 'exit', 'pid': os.getpid()})

  35. def main():
  36.     proc_pool = {} # 记录创建的所有子进程
  37.     cntl_q = mp.Queue() # 控制信息传递队列
  38.     data_q = mp.Queue() # 具体数据传递队列
  39.     exit_flag = mp.Event() # 退出标记,初始值为False

  40.     # 收到SIGINT,通知proxy停止读取数据
  41.     signal(SIGINT, lambda x, y: exit_flag.set())
  42.     siginterrupt(SIGINT, False)

  43.     # 启动proxy进程,后续按需启动woker进程
  44.     print 'main {} started'.format(os.getpid())
  45.     proc = mp.Process(target=proc_proxy, args=(cntl_q, data_q, exit_flag))
  46.     proc.start()
  47.     proc_pool[proc.pid] = proc
  48.     print 'proxy {} started'.format(proc.pid)

  49.     while True:
  50.         item = cntl_q.get()
  51.         if item['event'] == 'data':
  52.             proc = mp.Process(target=proc_worker, args=(cntl_q, data_q))
  53.             proc.start()
  54.             proc_pool[proc.pid] = proc
  55.             print 'worker {} started'.format(proc.pid)
  56.         elif item['event'] == 'exit':
  57.             proc = proc_pool.pop(item['pid'])
  58.             proc.join()
  59.             print 'child {} stopped'.format(item['pid'])
  60.         else:
  61.             print 'It\'s impossible !'

  62.         if not proc_pool: # 所有子进程均已退出
  63.             break

  64.     print 'main {} stopped'.format(os.getpid())

  65. if __name__ == '__main__':
  66.     main()
复制代码

论坛徽章:
60
20周年集字徽章-20	
日期:2020-10-28 14:04:3015-16赛季CBA联赛之北京
日期:2016-07-06 15:42:0715-16赛季CBA联赛之同曦
日期:2016-06-12 10:38:0915-16赛季CBA联赛之佛山
日期:2016-05-27 11:54:56黄金圣斗士
日期:2015-12-02 11:44:35白银圣斗士
日期:2015-11-25 14:32:43白银圣斗士
日期:2015-11-23 12:53:352015亚冠之布里斯班狮吼
日期:2015-10-21 16:55:482015亚冠之首尔
日期:2015-09-01 16:46:052015亚冠之德黑兰石油
日期:2015-08-31 11:39:192015亚冠之萨济拖拉机
日期:2015-08-28 21:06:5315-16赛季CBA联赛之广东
日期:2016-07-12 14:58:53
10 [报告]
发表于 2014-03-30 16:50 |只看该作者
回复 9# timespace


    太感谢啦,经过实际测试,完美符合我的需求,而且加入了信号控制,很完善!!   灰常感谢!

    关于你说的进程控制,我是在数据库层面,查询任务的时候做好了控制的,最多不会超过查询的任务数,所以不用担心。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP