什么是线程池?##
诸如web服务器、数据库服务器、文件服务器和邮件服务器等许多服务器应用都面向处理来自某些远程来源的大量短小的任务。构建服务器应用程序的一个过于简单的模型是:每当一个请求到达就创建一个新的服务对象,然后在新的服务对象中为请求服务。但当有大量请求并发访问时,服务器不断的创建和销毁对象的开销很大。所以提高服务器效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁,这样就引入了“池”的概念,“池”的概念使得人们可以定制一定量的资源,然后对这些资源进行复用,而不是频繁的创建和销毁。
线程池是预先创建线程的一种技术。线程池在还没有任务到来之前,创建一定数量的线程,放入空闲队列中。这些线程都是处于睡眠状态,即均为启动,不消耗CPU,而只是占用较小的内存空间。当请求到来之后,缓冲池给这次请求分配一个空闲线程,把请求传入此线程中运行,进行处理。当预先创建的线程都处于运行状态,即预制线程不够,线程池可以自由创建一定数量的新线程,用于处理更多的请求。当系统比较闲的时候,也可以通过移除一部分一直处于停用状态的线程。
线程池的注意事项
虽然线程池是构建多线程应用程序的强大机制,但使用它并不是没有风险的。在使用线程池时需注意线程池大小与性能的关系,注意并发风险、死锁、资源不足和线程泄漏等问题。
(1)线程池大小。多线程应用并非线程越多越好,需要根据系统运行的软硬件环境以及应用本身的特点决定线程池的大小。一般来说,如果代码结构合理的话,线程数目与CPU 数量相适合即可。如果线程运行时可能出现阻塞现象,可相应增加池的大小;如有必要可采用自适应算法来动态调整线程池的大小,以提高CPU 的有效利用率和系统的整体性能。
(2)并发错误。多线程应用要特别注意并发错误,要从逻辑上保证程序的正确性,注意避免死锁现象的发生。
(3)线程泄漏。这是线程池应用中一个严重的问题,当任务执行完毕而线程没能返回池中就会发生线程泄漏现象。
# coding: utf-8
# Author: WMX
# !/usr/bin/env python
from threading import Thread
from Queue import Queue
from bs4 import BeautifulSoup
import signal
import sys
import urllib2
import ssl
if hasattr(ssl, '_create_unverified_context'):
ssl._create_default_https_context = ssl._create_unverified_context
def get_title(ip):
try:
ip = ip.strip("\r\n")
print ip
req = urllib2.Request("http://" + ip)
resp = urllib2.urlopen(req, data=None, timeout=3)
respHtml = resp.read()
soup = BeautifulSoup(respHtml, 'lxml')
tables = soup.findAll('title')
print tables
ret = open("ret.txt", "a") # save ret
ret.write(ip + " " + str(tables) + "\n")
ret.close()
except Exception as e:
ret = open("ret.txt", "a") # save ret
ret.write(ip + " " + str(e) + "\n")
ret.close()
print e
class Worker(Thread):
def __init__(self, taskQueue):
Thread.__init__(self)
self.setDaemon(True)
self.taskQueue = taskQueue
self.start()
def run(self):
while 1:
try:
callable, args, kwds = self.taskQueue.get(block=False)
self.taskQueue.get(block=False)
print callable(*args, **kwds)
except:
break
class ThreadPool:
def __init__(self):
self.threads = []
self.taskQueue = Queue()
self.threadNum = num_thread
self.__create_taskqueue()
self.__create_threadpool(self.threadNum)
def __create_taskqueue(self):
f = open("d:\\port.txt", 'r') #要扫描的IP文件
lines = f.readlines()
for ip in lines:
self.add_task(get_title, ip)
def __create_threadpool(self, threadNum):
for i in range(threadNum):
thread = Worker(self.taskQueue)
self.threads.append(thread)
def add_task(self, callable, *args, **kwds):
self.taskQueue.put((callable, args, kwds))
def new_complete(self):
for item in self.threads:
if item.isAlive(): item.join()
def handler(signum, frame):
global is_exit
print "CTRL+C Is Pressed"
sys.exit(0)
if __name__ == '__main__':
num_thread = 20 #设置线程数
signal.signal(signal.SIGINT, handler)
signal.signal(signal.SIGTERM, handler)
tp = ThreadPool()
tp.new_complete()
网友评论