python多线程队列处理_Python线程和队列使用的一点思考

Python线程和队列使用的一点思考

1. 斗哥采访环节请问为什么要使用线程?

答:为了提高程序速度,代码效率呀。

请问为什么要使用队列?

答:个人认为队列可以保证线程安全,实现线程间的同步,比较稳。

线程为什么采用Threading模块?

答:据我所知还有Thread模块,该模块级别较低不推荐用。更高级别的是threading模块,它有一个Thread类,而且提供了各种非常好用的同步机制。

你所说的同步机制是指啥?

答:就是希望线程能够同时开跑,想象一下“所有的马同时冲出栅栏”的场景,就是我们说的同步了,而Therad模块的同步机制不佳亦是其不推荐使用的原因之一。

2. 需要用到线程的场景?

2.1 举个简单的案例,假设这么一个需求如下

给定200个IP地址,可能开放端口有80,443,7001,7002,8000,8080,8081,8888,9000,9001等,现需以'[[http://ip:port](http://ip:port)]([http://ip:port](http://ip:port))'形式访问页面以判断是否正常。

2.2 为什么要用线程解决这个需求?

200个ip地址和10个端口,累计请求2000次,一个个请求过去太慢,设定线程可以提高效率。

2.3 如果不用线程怎么样实现?

(以下仅为演示代码,如有错误敬请指出)**注:**将200个ip地址放到ip.txt记事本中,读取ip拼接端口并请求。#-*-coding:utf-8

import requests

portlist=[80,443,7001,7002,8000,8080,8081,8888,9000,9001]

ips=[t.replace("\n","") for t in open('ip.txt',"r").readlines()]

for ip in ips:

for port in portlist:

url="http://"+ip+':'+str(port)

try:

resp=requests.get(url=url,timeout=2)

print url,"mabey normal..."

except:

print url,"unknown wrong..."

注:运行上述代码,请求2000条url,每条等待超时2秒,差不多要1个多小时才能跑完,漫长的等待过程中渐渐失去笑容和耐心……

3. threading如何运用以解决上述问题?

使用threading模块的Thread类来创建线程,先要创建一个Thread的实例,传给它一个函数去跑线程。比如专门定义一个函数req()来请求URL,然后把这个req函数传给Thread的实例,接着开启线程……可以先看下面这段代码。(以下代码修改自上文)import requests

import threading

def req(url): #请求的代码写成一个函数

try:

resp=requests.get(url=url,timeout=2)

print url,"mabey normal..."

except:

print url,"unknown wrong..."

def main():

portlist=[80,443,7001,7002,8000,8080,8081,8888,9000,9001]

ips=[t.replace("\n","") for t in open('ip.txt',"r").readlines()]

urllist=[]

threads=[]

for ip in ips: #将url写到列表中

for port in portlist:

urllist.append("http://"+ip+':'+str(port))

for url in urllist: #将线程存到threads列表中

t=threading.Thread(target=req,args=(url,))

threads.append(t)

for t in threads: #开始跑线程,用while来控制线程数

t.start()

while True:

if(len(threading.enumerate())<100):

break

if __name__ == '__main__':

main()

其中, t=threading.Thread(target=req,args=(url,))的t就是一个Thread的实例了,args是可以加入到函数传递的参数,而本代码的req()函数需要传递参数是url。

你可以看到的是,这个代码建立了2000个未开始跑的线程放到threads列表里,接着遍历threads来开启线程。为了防止线程数过多,用while循环判断如果当前线程数len(threading.enumerate()超过了100则不开启下一个线程,也就是100指的是线程数。

3.1 简单评价下这个脚本

(有其他建议请留言评论)代码效果:线程设置成100,不到1分钟时间就跑完了整个脚本。

为了方便,将url写到了列表里,付出的代价是浪费了相应的内存空间。

线程数的控制使用while循环和threading.enumerate()来判断,不够优雅。

3.2 更好一点的方式:使用for循环来控制线程数+while循环结合列表的pop方法import requests

import threading

def req():

while True:

try:

url=urllist.pop()

except IndexError:

break

try:

resp=requests.get(url=url,timeout=2)

print url,"mabey normal..."

except:

print url,"unknown wrong..."

def main():

for i in range(10):

t=threading.Thread(target=req)

t.start()

for i in range(10):

t.join()

if __name__ == '__main__':

portlist=[80,443,7001,7002,8000,8080,8081,8888,9000,9001]

ips=[t.replace("\n","") for t in open('ip.txt',"r").readlines()]

urllist=[]

for ip in ips:

for port in portlist:

urllist.append("http://"+ip+':'+str(port))

main()

你可以发现上述代码大概有2点变化。线程的开启更加纯粹,不再有传递参数的功能。而多了个for循环来执行t.join(),这个是用来阻塞主线程,当开启的子线程未跑完时,主线程不往下继续执行。

参数url的获取,改成了url=urllist.pop()的方式,因为我们知道列表的pop方法会默认每次从列表移除最后一个元素并返回该元素的值,所以能够起到参数获取的作用。线程数的控制用for i in range(10)来开启,而不用while循环不停去检测线程数是不是超了。而参数获取完成了之后,列表也空了,似乎达到节省了空间,不过我们还是得事先准备一个列表,把url一个个预先填进去(如下图)。

如果不希望暂用那么大的空间,那么我们需要有一个缓存空间,并发的存入且能够并发读取而且不会发生阻塞,脑补一张图大概长下面这样:

上图描述就是人们常说的做生产者和消费者模式。在python中,Queue模块实现了多生产者多消费者队列, 尤其适合多线程编程.Queue类中实现了所有需要的锁原语,可以优雅的解决上述的问题,那么首先需要了解一下关于队列的一些细节……

4. 队列几点介绍

4.1 导入import Queue

from Queue import [Queue Class]

4.2 通用方法put(item(,block[,timeout]))从队列中放入item。

get()从队列移除并返回一个数据。(这个方法和列表的pop()方法是不是很像?)

empty()如果队列为空,返回True,反之返回False

task_done()task_done()告诉队列,get()方法的任务处理完毕。

join()阻塞调用线程,直到队列中的所有任务被处理掉。

4.3 队列模型(类)FIFO队列(First in First Out,先进先出)

class Queue.Queue(maxsize=0)

Queue提供了一个基本的FIFO容器,maxsize是个整数,指明了队列中能存放的数据个数的上限。一旦达到上限,插入会导致阻塞,直到队列中的数据被消费掉。如果maxsize小于或者等于0,队列大小没有限制。import Queue

q=Queue.Queue

for i in range(1,6):

q.put(i)

while not q.empty():

print q.get()

[console]

$ python queth.py

1

2

3

4

5

更多用法参考官方文档:Queue官方文档

4.4 多线程和Queue.Queue()

前面已经提到,参数的获取可以并发的实现,但是苦于一直没有找到合适的场景。我们在文章中提到的需求,你可以发现2000个url的获取通过个循环就可以轻易获取根本用不到生产者的模式,也就提现不出队列的强大,尽管如此我还是给出对应的脚本,你可以发现其实和用列表获取参数的差别并不大。(小伙伴有更好的场景欢迎提出来一起讨论呀)import requests

import threading

from Queue import Queue

def req(queue):

while True:

url=queue.get()

try:

resp=requests.get(url=url,timeout=2)

queue.task_done()

print url,"mabey normal..."

except:

print url,"unknown wrong..."

queue.task_done()

def get_url(queue):

portlist=[80,443,7001,7002,8000,8080,8081,8888,9000,9001]

ips=[t.replace("\n","") for t in open('ip.txt',"r").readlines()]

for ip in ips:

for port in portlist:

url="http://"+ip+':'+str(port)

queue.put(url,1)

def main():

queue=Queue()

get_url(queue)

for i in range(10):

t=threading.Thread(target=req,args=(queue,))

t.setDaemon(True)

t.start()

queue.join()

if __name__ == '__main__':

main()

你可以发现通过一个get_url()函数就轻易将url存储到队列中,我们在定义queue的时候是可以设定队列空间大小的,如queue=Queue(100),当存放了100个元素而未被取走时,队列会处于阻塞状态。不过设定队列大小上述代码就需要改写了,可以参考《Python核心编程》关于线程和队列的章节。

5. 小结

以上就是本次关于线程和队列思考的全部内容了,希望能够帮助到那些刚入门python的新手玩家们。本文也仅限斗哥的一点点小思考,也希望大家能够提出更好的见解和斗哥一起讨论。(The End)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/298293.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安装debian的zabbix-agent客户端

1. 下载软件源wget http://repo.zabbix.com/zabbix/2.2/debian/pool/main/z/zabbix-release/zabbix-release_2.2-1wheezy_all.deb2. 安装软件源dpkg -i zabbix-release_2.2-1wheezy_all.deb3. 更新软件源apt-get update4. 安装zabbix-agentapt-get install zabbix-agent其实deb…

看到喜欢的人时的心跳​

1 第一次和女孩子约会的猫咪.......好羞涩啊2 我要吃蛋糕&#xff01;不给买我就不走了~3 感觉自己活得都没小螃蟹精致4 完美的过程5 漫画真人6 哈哈哈哈哈哈真实合理慌的一批7 人最大的烦恼就是记性太好&#xff01;你点的每个赞&#xff0c;我都认真当成了喜欢

[Buzz.Today]2011.06.26

>> Microsoft推出Kinect for Windows SDK Kinect这玩意不得了&#xff0c;号称刚出世时比iPad和iPhone还卖得好。和当年iPhone一样&#xff0c;这玩意颇受一堆Hacker的青睐&#xff0c;做出了很多很炫的东西。 Piaoger当年曾经做过VR&#xff0c;虽然没搞出什么名堂&…

ARM公版架构迭代迅速 国产ARM架构落伍

近年来&#xff0c;ARM CPU性能可谓是突飞猛进&#xff0c;根据ARM官方消息&#xff0c;Cortex A78 CPU最高性能比5年前推出的Cortex A73 CPU提升2.5倍。ARM下一代的Matterhorn架构及Makalu架构会相对于X1/A78这一代保持30%以上的IPC性能提升&#xff0c;如果ARM的PPT不注水&am…

python 字符编码处理_浅析Python 字符编码与文件处理

Python字符编码目前计算机内存的字符编码都是Unicode&#xff0c;目前国内的windows操作系统采用的是gbk。python2默认的字符编码方式是ASCIIpython3默认的字符编码方式是Unicode.py文件头部的#coding:utf-8是帮助python识别.py文件的编码方式&#xff0c;故在写.py文件时要注意…

java 匿名初始化_关于java匿名内部类初始化法

最近无意间发现一种对象的初始化方法&#xff1a;匿名内部类初始化法List list new ArrayList(){{add("爱飘de小子");add("flyingkid");}};Map map new HashMap(){{put("name","爱飘de小子");put("age",24);}};还有这种操…

感谢生活的磨砺

感谢伤害你的人&#xff0c;因为他磨炼了你的心志&#xff01;  感谢绊倒你的人&#xff0c;因为他强化了你的双腿&#xff01;  感谢欺骗你的人&#xff0c;因为他增进了你的智慧&#xff01;  感谢藐视你的人&#xff0c;因为他觉醒了你的自尊&#xff01;  感谢遗弃…

MemoryCache 使用不当导致的一个 BUG

MemoryCache 使用不当导致的一个 BUGIntro前几天发现代码里的一个 BUG&#xff0c;原因是 MemoryCache 使用不当&#xff0c;可以对于很多人来说可能都知道&#xff0c;但还是想分享记录一下&#xff0c;避免以后写出同样的 BUGSample直接来看下面的示例吧await using var serv…

Llinux 磁盘配额的搭建和常规问题解答

1 磁盘配额的使用限制仅针对整个分区&#xff1a;磁盘配额实际运行时&#xff0c;是针对“整个分区”进行限制的&#xff0c;例如&#xff0c;如果/dev/hda5载入在/home下&#xff0c;那么&#xff0c;在/home下面的所有目 录都会受到限制。只对一般身份用户有效&#xff1a;并…

22岁少年破解史上最严重网络攻击,拯救全球互联网,三个月后却被FBI逮捕

转自&#xff1a;大数据文摘编译&#xff1a;牛婉杨2017年&#xff0c;一位名叫Marcus Hutchins的少年从有史以来最严重的网络攻击事件“WannaCry 勒索病毒”中拯救了互联网。如果你是个geek&#xff0c;那么你对WannaCry这个名字一定不陌生&#xff0c; 这是一种可以自行传播的…

python安装beautifulsoup失败_Win10环境下python36安装BeautifulSoup出现错误的解决办法

说明&#xff1a;win10 64位系统&#xff0c;Python3.6.3Win10环境下安装BeautifulSoup4貌似没有任何问题&#xff0c;但是当使用时就会报错&#xff0c;错误如下&#xff1a;通过报错信息到相应的位置去查看文件try:is_file os.path.exists(possible_filename)except Excepti…

使用 Git Extensions 简单入门 Git

使用 Git Extensions 简单入门 Git—— 独立观察员 2015.11.25前言关于这个主题&#xff0c;之前我录了段视频教程&#xff0c;在本地看清晰度还可以&#xff0c;但传到优酷上就很不清晰了&#xff0c;即使是后来重制后还是一样不清晰&#xff0c;所以现在想整理成文字版。当然…

各省地图都像些什么?

全世界只有3.14 % 的人关注了爆炸吧知识人们常说中国地图的形状像一只雄鸡&#xff0c;但具体到每一个省区则并没有一个明确的说法。看看下面这一套省区地图对应的有趣的想象&#xff0c;你觉得像还是不像&#xff1f;★安徽有人说安徽像一只斜倒挂着的蝙蝠&#xff0c;你能看出…

android 蓝牙各种UUID(转载)

android 蓝牙各种UUID ServiceDiscoveryServerServiceClassID_UUID {00001000-0000-1000-8000-00805F9B34FB} BrowseGroupDescriptorServiceClassID_UUID {00001001-0000-1000-8000-00805F9B34FB} PublicBrowseGroupServiceClass_UUID {00001002-0000-1000-8000-00805F9B34F…

Silverlight中摄像头的运用—part2

Silverlight 4 中摄像头的运用—part1将跟踪颜色视作输入 好了&#xff0c;我们能够跟踪到这个颜色了&#xff0c;那这么做的意义是什么呢&#xff1f;实际上&#xff0c;我们可以根据它的位置来移动东西。接下来的例子中&#xff0c;创建的一个球会跟随这个颜色一起移动。你可…

python静态变量和静态方法_python的静态成员变量、实例成员变量、静态方法、类方法、实例方法...

标签&#xff1a;静态成员变量(类变量)和普通成员变量(实例变量)静态成员变量只能通过类名.变量名获得&#xff0c;实例成员变量&#xff0c;通过该实例引用.变量名获得。在实例对静态成员变量赋值时&#xff0c;实例python是动态类型的语言&#xff0c;没有特别的标志区分静态…

同学,解决下这个 Bug!

一些解决 Bug 的小技巧大家好&#xff0c;我是鱼皮。学编程的过程中&#xff0c;我们会遇到各式各样的 Bug&#xff0c;也常常因为它们而感到头秃。但随着你不断解决 Bug、积累经验&#xff0c;就会发现其实解决 Bug 也是有套路的。今天分享下鱼皮自己总结的解决 Bug 套路&…

C#编写串口通信程序(转)

一&#xff0e;概述 在Visual Studio 6.0中编写串口通讯程序&#xff0c;一般都使用Microsoft Communication Control&#xff08;简称MSComm&#xff09;的通讯控件&#xff0c;只要通 过对此控件的属性和事件进行相应编程操作&#xff0c;就可以轻松地实现串口通讯。但在Micr…

pfsense下的流量管理(转)

http://www.pppei.net/blog/post/331 在作流量管理时&#xff0c;这些概念很重要&#xff0c;不要迷失。。 这里再对Limiter 的源地址和目的地址做个说明&#xff0c;因为limiter是被应用在Lan接口的Rule里&#xff0c;相对pfsense来说&#xff0c;用户发往 Lan口的流量为In&am…