最近使用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'
運行過程圖文解釋如下:
程序未運行,系統的線程狀態如下,top -H顯示如下:系統當前共有592個線程,其中1個處於運行狀態,其他的處於sleep狀態
運行系統,但是多線程任務還沒有執行完畢,in_queue和out_queue隊列還是阻塞狀態,top -H 顯示如下: 這時系統中共有1480個線程,也就是說我的程序創建1480-592 +1= 889個線程,理論上會創建255*2= 510個線程,至於多創建多出來的889-510 = 379個線程,我猜是subprocescess 調用系統的ping命令先關,再次不考慮這379個線程的情況,只考慮510個線程的去向...但是這個不是重點,這個階段,兩個隊列還時處於阻塞狀態,創建的多線程還未全部返回
in_queue和out_queue兩個隊列不在阻塞主進程,多線程任務執行完成,get_all_device_status(ips)已經有了返回值,主進程沉睡20秒,shell顯示如下:主進程因爲time.sleep(20)進入20秒的睡眠中,這時top -H 顯示如下:in_queue和out_queue已經不再阻塞主進程了,任務也有了返回值,但是顯示共有1101個線程,也就是還剩餘1101-592+1 = 510 也就是subprocess那30多哥線程已經退出了,但是程序創建的510個線程一個都沒有退出...
主進程沉睡20秒,退出,程序運行完畢,住進成退出,它所創建的所有線程均已退出,當前系統中線程的數目爲:590,也就是1101-590+1 = 512個線程,在主進程退出後才退出...top -H顯示如下:這就是問題,如果主進程沉睡的時間更長,比如一年,那麼再一年內,所有的線程都不會退出,更早的是,如果重複運行該程序,每次創建的510個線程,均不能退出....這樣早晚會把操作系統分配給當前用戶的最大線程數目用完(ulimit -n)...到時候,該用戶所有操作,均不能使用....
總結,按照我現在的代碼,就是線程執行任務完後,還是會存在,狀態編程sleeping狀態,只有主進程退出才能退出....但是如果用flask或者django調用多線程的時候,由於flask和django等輕易不會退出...所以就會出現我說的那個問題...所以說,怎麼才能使用threading queue 任務有返回之後,主進程殺死所創建的線程.....?
有解決方案的,可以把代碼貼在評論裏面, 多謝!