最近使用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 任务有返回之后,主进程杀死所创建的线程.....?
时间: 2024-12-07 15:33:36