zoukankan      html  css  js  c++  java
  • 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()   清空队列

  • 相关阅读:
    Nginx浅谈
    MySQL 规范
    使用nginx反向代理实现隐藏端口号
    -bash: /etc/profile: line 11: syntax error near unexpected token `$'{ ''报错问题解决
    为什么禁止在 foreach 循环里进行元素的 remove/add 操作
    Java中String字符串常量池
    前端学习路径
    Linux关闭防火墙命令
    CXF实现webService服务
    Jquery Ajax 的例子。
  • 原文地址:https://www.cnblogs.com/cj2014/p/4143578.html
Copyright © 2011-2022 走看看