一. python非阻塞編程的settimeout與setblocking+selectphp
原文:www.th7.cn/Program/Python/201406/214922.shtmlhtml
側面認證Python的settimeout確實應該是非阻塞,此次使用select+setblocking和settimeout來作個對比,以此來證實。python
首先我設置socket爲非阻塞的。而後使用select來監控套接字。編程
#!/usr/bin/env python
# encoding: utf-8
import socket
import threading
import Queue
import time
import select
class worker(threading.Thread):
def __init__(self,name,queue):
self.data=queue
super(worker,self).__init__(name=name)
def run(self):
for i in range(10000):
self.data.put(i)
class customer(threading.Thread):
def __init__(self,name,queue):
super(customer,self).__init__(name=name)
self.data=queue
def scan(self,ip,port):
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setblocking(False) #non_blocking
#s.settimeout(0.1)
results=s.connect_ex((ip,port))
#print results
a,b,c=select.select([],[s,],[s,],0.1)#設置超時時間0.1秒,這裏我根據前面博文的總結得出來的。
#當connect鏈接成功的時候,表明Tcp3次握手完成,此時變成可寫狀態
if b:#若是socket可寫,表明了端口是開放的
print port
s.close()
def run(self):
while True:
try:
a=self.data.get(1,5)
except:
break
else:
ip='220.181.136.241'
self.scan(ip,a)
def main():
start=time.time()
queue=Queue.Queue()
pool=[]
worke=worker('firebroo',queue)
worke.start()
for i in range(100):
a=customer('firebroo',queue)
pool.append(a)
for i in pool:
i.start()
worke.join()
for i in pool:
i.join()
print time.time()-start
del pool[:]
if __name__=='__main__':
main()
大概花費17.5秒執行完畢。下面我使用settimeout。app
#!/usr/bin/env python
# encoding: utf-8
import socket
import threading
import Queue
import time
import select
class worker(threading.Thread):
def __init__(self,name,queue):
self.data=queue
super(worker,self).__init__(name=name)
def run(self):
for i in range(10000):
self.data.put(i)
class customer(threading.Thread):
def __init__(self,name,queue):
super(customer,self).__init__(name=name)
self.data=queue
def scan(self,ip,port):
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#s.setblocking(False)
s.settimeout(0.1)#爲了和前面保持一致,固然得設置0.1秒
results=s.connect_ex((ip,port))
if results==0:#connect_ex中0表明端口開放,3次握手完成
print port
#print results
#a,b,c=select.select([],[s,],[s,],0.1)#設置超時時間0.1秒,這裏我根據前面博文的總結得出來的。
#當connect鏈接成功的時候,表明Tcp3次握手完成,此時變成可寫狀態
#if b:#若是socket可寫,表明了端口是開放的
# print port
s.close()
def run(self):
while True:
try:
a=self.data.get(1,5)
except:
break
else:
ip='220.181.136.241'
self.scan(ip,a)
def main():
start=time.time()
queue=Queue.Queue()
pool=[]
worke=worker('firebroo',queue)
worke.start()
for i in range(100):
a=customer('firebroo',queue)
pool.append(a)
for i in pool:
i.start()
worke.join()
for i in pool:
i.join()
print time.time()-start
del pool[:]
if __name__=='__main__':
main()
時間大概是17.4。這兩個測試結果應該能夠說是同樣的,不免會有偏差。socket
總結:由此我能夠說Python的settimeout這個API確實是非阻塞。和select+setblocking效果是同樣的測試
二. Python Queue的使用ui
原文:doudouclever.blog.163.com/blog/static/1751123102012111192621448/url
python 中,隊列是線程間最經常使用的交換數據的形式。Queue模塊是提供隊列操做的模塊,雖然簡單易用,可是不當心的話,仍是會出現一些意外。spa
1. 阻塞模式致使數據污染
import Queue
q = Queue.Queue(10)
for i in range(10):
myData = 'A'
q.put(myData)
myData = 'B'
這 是一段極其簡單的代碼,但我老是不能得到指望的結果(指望在隊列中寫入10個A,卻老是混雜了B)。原來,Queue.put()默認有 block = True 和 timeou 兩個參數。當 block = True 時,寫入是阻塞式的,阻塞時間由 timeou 肯定。正由於阻塞,才致使了後來的賦值污染了處於阻塞狀態的數據。Queue.put()方法加上 block=False 的參數,便可解決這個隱蔽的問題。但要注意,非阻塞方式寫隊列,當隊列滿時會拋出 exception Queue.Full 的異常。
2. 沒法捕獲 exception Queue.Empty 的異常
while True:
......
try:
data = q.get()
except Queue.Empty:
break
我 的本意是用隊列爲空時,退出循環,但實際運行起來,卻陷入了死循環。這個問題和上面有點相似:Queue.get()默認的也是阻塞方式讀取數據,隊列爲 空時,不會拋出 except Queue.Empty ,而是進入阻塞直至超時。 加上block=False 的參數,問題迎刃而解。
3. Queue經常使用方法彙總
Queue.Queue(maxsize=0) FIFO, 若是maxsize小於1就表示隊列長度無限
Queue.LifoQueue(maxsize=0) LIFO, 若是maxsize小於1就表示隊列長度無限
Queue.qsize() 返回隊列的大小
Queue.empty() 若是隊列爲空,返回True,反之False
Queue.full() 若是隊列滿了,返回True,反之False
Queue.get([block[, timeout]]) 讀隊列,timeout等待時間
Queue.put(item, [block[, timeout]]) 寫隊列,timeout等待時間
Queue.queue.clear() 清空隊列