python socket非阻塞及python隊列Queue


一. python非阻塞編程的settimeout與setblocking+select

原文:www.th7.cn/Program/Python/201406/214922.shtml

側面認證Python的settimeout確實應該是非阻塞,這次使用select+setblocking和settimeout來做個對比,以此來證明。

首先我設置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。

#!/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。這兩個測試結果應該可以說是一樣的,難免會有誤差。

總結:由此我可以說Python的settimeout這個API確實是非阻塞。和select+setblocking效果是一樣的

 

二. Python Queue的使用

原文:doudouclever.blog.163.com/blog/static/1751123102012111192621448/

python 中,隊列是線程間最常用的交換數據的形式。Queue模塊是提供隊列操作的模塊,雖然簡單易用,但是不小心的話,還是會出現一些意外。

       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()   清空隊列


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM