博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python 多线程剖析
阅读量:5088 次
发布时间:2019-06-13

本文共 3575 字,大约阅读时间需要 11 分钟。

先来看个栗子:

下面来看一下I/O秘籍型的线程,举个栗子——爬虫,下面是爬下来的图片用4个线程去写文件

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3   4 import re 5 import urllib 6 import threading 7 import Queue 8 import timeit 9 10 def getHtml(url):11     html_page = urllib.urlopen(url).read()12     return html_page13  14 # 提取网页中图片的URL15 def getUrl(html):16     pattern = r'src="(http://img.*?)"'  # 正则表达式17     imgre = re.compile(pattern)18     imglist = re.findall(imgre, html)  # re.findall(pattern,string)  在string中寻找所有匹配成功的字符串,以列表形式返回值19     return imglist20  21 class getImg(threading.Thread):22     def __init__(self, queue, thread_name=0):  # 线程公用一个队列23         threading.Thread.__init__(self)24         self.queue = queue25         self.thread_name = thread_name26         self.start()  # 启动线程27  28     # 使用队列实现进程间通信29     def run(self):30         global count31         while (True):32             imgurl = self.queue.get() # 调用队列对象的get()方法从队头删除并返回一个项目33             urllib.urlretrieve(imgurl, 'E:\mnt\girls\%s.jpg' % count)34             count += 135             if self.queue.empty():36                 break37             self.queue.task_done()  # 当使用者线程调用 task_done() 以表示检索了该项目、并完成了所有的工作时,那么未完成的任务的总数就会减少。38 imglist = []39 def main():40     global imglist41     url = "http://huaban.com/favorite/beauty/"  # 要爬的网页地址42     html = getHtml(url)43     imglist = getUrl(html)44  45 def main_1():46     global count47     threads = []48     count = 049     queue = Queue.Queue()50     # 将所有任务加入队列51     for img in imglist:52         queue.put(img)53     # 多线程爬去图片54     for i in range(4):55         thread = getImg(queue, i)56         threads.append(thread)57     # 阻塞线程,直到线程执行完成58     for thread in threads:59         thread.join()60  61 if __name__ == '__main__':62     main()63     t = timeit.Timer(main_1)64     print t.timeit(1)

4个线程的执行耗时为:0.421320716723秒

修改一下main_1换成单线程的:

1 def main_1(): 2     global count 3     threads = [] 4     count = 0 5     queue = Queue.Queue() 6     # 将所有任务加入队列 7     for img in imglist: 8         queue.put(img) 9     # 多线程爬去图片10     for i in range(1):11         thread = getImg(queue, i)12         threads.append(thread)13     # 阻塞线程,直到线程执行完成14     for thread in threads:15         thread.join()

 

单线程的执行耗时为:1.35626623274秒

再来看一个:

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import threading 4 import timeit 5  6 def countdown(n): 7     while n > 0: 8         n -= 1 9 10 def task1():11     COUNT = 10000000012     thread1 = threading.Thread(target=countdown, args=(COUNT,))13     thread1.start()14     thread1.join()15 16 def task2():17     COUNT = 10000000018     thread1 = threading.Thread(target=countdown, args=(COUNT // 2,))19     thread2 = threading.Thread(target=countdown, args=(COUNT // 2,))20     thread1.start()21     thread2.start()22     thread1.join()23     thread2.join()24 25 if __name__ == '__main__':26     t1 = timeit.Timer(task1)27     print "countdown in one thread ", t1.timeit(1)28     t2 = timeit.Timer(task2)29     print "countdown in two thread ", t2.timeit(1)

 

task1是单线程,task2是双线程,在我的4核的机器上的执行结果:

countdown in one thread  3.59939150155

countdown in two thread  9.87704289712

天呐,双线程比单线程计算慢了2倍多,这是为什么呢,因为countdown是CPU密集型任务(计算嘛)

  I/O密集型任务:线程做I/O处理的时候会释放GIL,其他线程获得GIL,当该线程再做I/O操作时,又会释放GIL,如此往复;

  CPU密集型任务:在多核多线程比单核多线程更差,原因是单核多线程,每次释放GIL,唤醒的哪个线程都能获取到GIL锁,所以能够无缝执行(单核多线程的本质就是顺序执行),但多核,CPU0释放GIL后,其他CPU上的线程都会进行竞争,但GIL可能会马上又被CPU0(CPU0上可能不止一个线程)拿到,导致其他几个CPU上被唤醒后的线程会醒着等待到切换时间后又进入待调度状态,这样会造成线程颠簸(thrashing),导致效率更低。

 

 

作者:
出处:
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载于:https://www.cnblogs.com/onepiece-andy/p/python-thread-analyze.html

你可能感兴趣的文章
散列表的ASL计算
查看>>
Leetcode 394: Decode String
查看>>
UVA-10082 WERTYU
查看>>
同步和互斥有什么联系和区别。
查看>>
使用GDI+ DrawDriverString实现行距及字符间距控制
查看>>
Windows 2012 安装 Oracle 11g 报错:[INS-13001]环境不满足最低要求。
查看>>
oracle 在C# 中调用oracle的数据库时,出现引用库和当前客户端不兼容的问题解决方案...
查看>>
ConsoleWebsocketServer服务端和ConsoleWebsocketClient客户端
查看>>
【读书笔记】iOS-ARC-循环引用-解决办法
查看>>
Py4J -- python和Java互调接口
查看>>
01-redis安装
查看>>
登陆界面实现输错3次锁定
查看>>
Windows Phone开发基础 (5)判断Windows phone 手机是否联网
查看>>
【EntityFramwork--处理数据并发问题】
查看>>
MyBatis学习总结(一)——MyBatis入门学习
查看>>
Hotels杂志
查看>>
Niginx反向代理负载均衡
查看>>
Linux/Unix下的任务管理器-top命令
查看>>
必须掌握的八个【cmd 命令行】
查看>>
BZOJ 1876: [SDOI2009]SuperGCD( 更相减损 + 高精度 )
查看>>