python threading父进程不死,子线程不退出..如何才能使用完线程后回收线程?

最近使用python的多线程 进行并发的ping操作,其中使用in_queue和out_queue两个阻塞队列,来确保线程安全.发现一个问题,

就是,创建多线程的主进程只要不退出,它(主进程)所创建的所有线程不会被杀死,只是状态均为sleeping状态而已,这样会有一个问题,就是linux系统分配给每个用户所开进程最大数目是有限制的,如果一个进程比如flask或者django在运行后,理论上不会退出的,这样会创建出越来越多的线程,早晚会达到上限,这样系统不能分配任何资源给这个用户了....

代码如下:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

from threading import Thread 
import subprocess 
from Queue import Queue, Empty
import re 
import sys,os,time 
import platform 

def ping(
    hostname = None,
    count = 1,
    timeout = 3
):
    data = {
        'errorcode':0xff,
        'errorinfo':None,
        'data':{
            'hostname':hostname,
            'isUp':None
        }
    }
    try:
        outfile = ''
        if "Linux" == platform.system():
            cmd = "ping -c %d -w %d %s"%(count,timeout,hostname)
            outfile = "/dev/null"
        elif "Windows" == platform.system():
            cmd = "ping -n %d -w %d %s"%(count,timeout,hostname)
            outfile = "ping.temp"
        ret = subprocess.call(cmd, shell=True, stdout=open(outfile,'w'), stderr=subprocess.STDOUT)
        data['data']['isUp'] = True if 0 == ret else False
        data['errorcode'] = 0x00
    except Exception,e:
        print traceback.format_exc()
    finally:
        return data
        
        
        
def ping_with_queue(in_queue, out_queue):
    while True:
        ip = in_queue.get()
        data = ping(hostname = ip)
        out_queue.put(data)
        in_queue.task_done()#向任务已完成的队列,发送一个通知信号


def append_result(out_queue, result):
    while True:
        data = out_queue.get()
        result.append(data)
        out_queue.task_done()#向任务已完成的队列,发送一个通知信号

        
        
def get_all_device_status(ips):
    data = {
        'errorcode':0xff,
        'errorinfo':None,
        'data':[]
    }
    result = []
    threads_nums = len(ips)
    in_queue = Queue()
    out_queue = Queue()
    for i in range(threads_nums):
        t = Thread(target=ping_with_queue, args=(in_queue,out_queue))
        t.setDaemon(True)
        t.start()
        
    for ip in ips:
        in_queue.put(ip)

    for i in range(threads_nums):
        t = Thread(target=append_result, args=(out_queue,data['data']))
        t.setDaemon(True)
        t.start()
    data['errorcode'] = 0x00
    in_queue.join()
    out_queue.join()
    return data

if __name__ == '__main__':
    ips = [ '10.1.31.'+str(i) for i in xrange(0xff)]
    print get_all_device_status(ips)
    print 'main process begin sleep 20 seconds....'
    time.sleep(20)
    print 'main process exit'


运行过程图文解释如下:

  1. 程序未运行,系统的线程状态如下,top -H显示如下:系统当前共有592个线程,其中1个处于运行状态,其他的处于sleep状态wKioL1ixjMDx2qyiAAJXqWjelrE890.jpg

  2. 运行系统,但是多线程任务还没有执行完毕,in_queue和out_queue队列还是阻塞状态,top -H 显示如下: 这时系统中共有1480个线程,也就是说我的程序创建1480-592 +1= 889个线程,理论上会创建255*2= 510个线程,至于多创建多出来的889-510 = 379个线程,我猜是subprocescess 调用系统的ping命令先关,再次不考虑这379个线程的情况,只考虑510个线程的去向...但是这个不是重点,这个阶段,两个队列还时处于阻塞状态,创建的多线程还未全部返回wKioL1ixjrmhDbDgAAJS8E29rUw042.jpg

  3. in_queue和out_queue两个队列不在阻塞主进程,多线程任务执行完成,get_all_device_status(ips)已经有了返回值,主进程沉睡20秒,shell显示如下:wKioL1ixkwTzQar3AATC_HWbwSE831.jpg主进程因为time.sleep(20)进入20秒的睡眠中,这时top -H 显示如下:in_queue和out_queue已经不再阻塞主进程了,任务也有了返回值,但是显示共有1101个线程,也就是还剩余1101-592+1 = 510 也就是subprocess那30多哥线程已经退出了,但是程序创建的510个线程一个都没有退出...wKioL1ixlPPDe-b7AAJN3DdHW6Q853.jpg

  4. 主进程沉睡20秒,退出,程序运行完毕,住进成退出,它所创建的所有线程均已退出,当前系统中线程的数目为:590,也就是1101-590+1 = 512个线程,在主进程退出后才退出...top -H显示如下:wKiom1ixlqaS6NzMAAJF2W77DrU819.jpg这就是问题,如果主进程沉睡的时间更长,比如一年,那么再一年内,所有的线程都不会退出,更早的是,如果重复运行该程序,每次创建的510个线程,均不能退出....这样早晚会把操作系统分配给当前用户的最大线程数目用完(ulimit -n)...到时候,该用户所有操作,均不能使用....

  5. 总结,按照我现在的代码,就是线程执行任务完后,还是会存在,状态编程sleeping状态,只有主进程退出才能退出....但是如果用flask或者django调用多线程的时候,由于flask和django等轻易不会退出...所以就会出现我说的那个问题...所以说,怎么才能使用threading queue 任务有返回之后,主进程杀死所创建的线程.....?


有解决方案的,可以把代码贴在评论里面, 多谢!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章