python3socket非阻塞_python socket非阻塞及python队列Queue

一. python非阻塞编程的settimeout与setblocking+select

侧面认证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的使用

python 中,队列是线程间最常用的交换数据的形式。Queue模块是提供队列操作的模块,虽然简单易用,但是不小心的话,还是会出现一些意外。

1. 阻塞模式导致数据污染

importQueue

q = Queue.Queue(10)

fori inrange(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 的异常

whileTrue:

......

try:

data = q.get()

exceptQueue.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() 清空队列

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值