什么是線(xiàn)程池惯豆?##
諸如web服務(wù)器害淤、數(shù)據(jù)庫(kù)服務(wù)器挖息、文件服務(wù)器和郵件服務(wù)器等許多服務(wù)器應(yīng)用都面向處理來(lái)自某些遠(yuǎn)程來(lái)源的大量短小的任務(wù)据块。構(gòu)建服務(wù)器應(yīng)用程序的一個(gè)過(guò)于簡(jiǎn)單的模型是:每當(dāng)一個(gè)請(qǐng)求到達(dá)就創(chuàng)建一個(gè)新的服務(wù)對(duì)象码邻,然后在新的服務(wù)對(duì)象中為請(qǐng)求服務(wù)。但當(dāng)有大量請(qǐng)求并發(fā)訪(fǎng)問(wèn)時(shí)另假,服務(wù)器不斷的創(chuàng)建和銷(xiāo)毀對(duì)象的開(kāi)銷(xiāo)很大冒滩。所以提高服務(wù)器效率的一個(gè)手段就是盡可能減少創(chuàng)建和銷(xiāo)毀對(duì)象的次數(shù),特別是一些很耗資源的對(duì)象創(chuàng)建和銷(xiāo)毀浪谴,這樣就引入了“池”的概念开睡,“池”的概念使得人們可以定制一定量的資源因苹,然后對(duì)這些資源進(jìn)行復(fù)用,而不是頻繁的創(chuàng)建和銷(xiāo)毀篇恒。
線(xiàn)程池是預(yù)先創(chuàng)建線(xiàn)程的一種技術(shù)扶檐。線(xiàn)程池在還沒(méi)有任務(wù)到來(lái)之前,創(chuàng)建一定數(shù)量的線(xiàn)程胁艰,放入空閑隊(duì)列中款筑。這些線(xiàn)程都是處于睡眠狀態(tài),即均為啟動(dòng)腾么,不消耗CPU奈梳,而只是占用較小的內(nèi)存空間。當(dāng)請(qǐng)求到來(lái)之后解虱,緩沖池給這次請(qǐng)求分配一個(gè)空閑線(xiàn)程攘须,把請(qǐng)求傳入此線(xiàn)程中運(yùn)行,進(jìn)行處理殴泰。當(dāng)預(yù)先創(chuàng)建的線(xiàn)程都處于運(yùn)行狀態(tài)于宙,即預(yù)制線(xiàn)程不夠,線(xiàn)程池可以自由創(chuàng)建一定數(shù)量的新線(xiàn)程悍汛,用于處理更多的請(qǐng)求捞魁。當(dāng)系統(tǒng)比較閑的時(shí)候,也可以通過(guò)移除一部分一直處于停用狀態(tài)的線(xiàn)程离咐。
線(xiàn)程池的注意事項(xiàng)
雖然線(xiàn)程池是構(gòu)建多線(xiàn)程應(yīng)用程序的強(qiáng)大機(jī)制谱俭,但使用它并不是沒(méi)有風(fēng)險(xiǎn)的。在使用線(xiàn)程池時(shí)需注意線(xiàn)程池大小與性能的關(guān)系宵蛀,注意并發(fā)風(fēng)險(xiǎn)旺上、死鎖、資源不足和線(xiàn)程泄漏等問(wèn)題糖埋。
(1)線(xiàn)程池大小。多線(xiàn)程應(yīng)用并非線(xiàn)程越多越好窃这,需要根據(jù)系統(tǒng)運(yùn)行的軟硬件環(huán)境以及應(yīng)用本身的特點(diǎn)決定線(xiàn)程池的大小瞳别。一般來(lái)說(shuō),如果代碼結(jié)構(gòu)合理的話(huà)杭攻,線(xiàn)程數(shù)目與CPU 數(shù)量相適合即可祟敛。如果線(xiàn)程運(yùn)行時(shí)可能出現(xiàn)阻塞現(xiàn)象,可相應(yīng)增加池的大姓捉狻馆铁;如有必要可采用自適應(yīng)算法來(lái)動(dòng)態(tài)調(diào)整線(xiàn)程池的大小,以提高CPU 的有效利用率和系統(tǒng)的整體性能锅睛。
(2)并發(fā)錯(cuò)誤埠巨。多線(xiàn)程應(yīng)用要特別注意并發(fā)錯(cuò)誤历谍,要從邏輯上保證程序的正確性,注意避免死鎖現(xiàn)象的發(fā)生辣垒。
(3)線(xiàn)程泄漏望侈。這是線(xiàn)程池應(yīng)用中一個(gè)嚴(yán)重的問(wèn)題,當(dāng)任務(wù)執(zhí)行完畢而線(xiàn)程沒(méi)能返回池中就會(huì)發(fā)生線(xiàn)程泄漏現(xiàn)象勋桶。
# 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 #設(shè)置線(xiàn)程數(shù)
signal.signal(signal.SIGINT, handler)
signal.signal(signal.SIGTERM, handler)
tp = ThreadPool()
tp.new_complete()