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 任務有返回之後,主進程殺死所創建的線程.....?


有解決方案的,可以把代碼貼在評論裏面, 多謝!


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