最近使用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显示如下:
https://s4.51cto.com/wyfs02/M02/8D/F8/wKioL1ixkwTzQar3AATC_HWbwSE831.jpg主进程因为time.sleep(20)进入20秒的睡眠中,这时top
-H
显示如下:in_queue和out_queue已经不再阻塞主进程了,任务也有了返回值,但是显示共有1101个线程,也就是还剩余1101-592+1
= 510 也就是subprocess那30多哥线程已经退出了,但是程序创建的510个线程一个都没有退出...
https://s5.51cto.com/wyfs02/M02/8D/F8/wKioL1ixlPPDe-b7AAJN3DdHW6Q853.jpg
主进程沉睡20秒,退出,程序运行完毕,住进成退出,它所创建的所有线程均已退出,当前系统中线程的数目为:590,也就是1101-590+1 = 512个线程,在主进程退出后才退出...top -H显示如下:
https://s2.51cto.com//wyfs02/M00/8D/FA/wKiom1ixlqaS6NzMAAJF2W77DrU819.jpg这就是问题,如果主进程沉睡的时间更长,比如一年,那么再一年内,所有的线程都不会退出,更早的是,如果重复运行该程序,每次创建的510个线程,均不能退出....这样早晚会把操作系统分配给当前用户的最大线程数目用完(ulimit
-n)...到时候,该用户所有操作,均不能使用....
总结,按照我现在的代码,就是线程执行任务完后,还是会存在,状态编程sleeping状态,只有主进程退出才能退出....但是如果用flask或者django调用多线程的时候,由于flask和django等轻易不会退出...所以就会出现我说的那个问题...所以说,怎么才能使用threading
queue 任务有返回之后,主进程杀死所创建的线程.....?
有解决方案的,可以把代码贴在评论里面, 多谢!