Python多线程原理与用法实例剖析


Posted in Python onJanuary 22, 2019

本文实例讲述了Python多线程原理与用法。分享给大家供大家参考,具体如下:

先来看个栗子:

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
import urllib
import threading
import Queue
import timeit
def getHtml(url):
  html_page = urllib.urlopen(url).read()
  return html_page
# 提取网页中图片的URL
def getUrl(html):
  pattern = r'src="(http://img.*?)"' # 正则表达式
  imgre = re.compile(pattern)
  imglist = re.findall(imgre, html) # re.findall(pattern,string) 在string中寻找所有匹配成功的字符串,以列表形式返回值
  return imglist
class getImg(threading.Thread):
  def __init__(self, queue, thread_name=0): # 线程公用一个队列
    threading.Thread.__init__(self)
    self.queue = queue
    self.thread_name = thread_name
    self.start() # 启动线程
  # 使用队列实现进程间通信
  def run(self):
    global count
    while (True):
      imgurl = self.queue.get() # 调用队列对象的get()方法从队头删除并返回一个项目
      urllib.urlretrieve(imgurl, 'E:\mnt\girls\%s.jpg' % count)
      count += 1
      if self.queue.empty():
        break
      self.queue.task_done() # 当使用者线程调用 task_done() 以表示检索了该项目、并完成了所有的工作时,那么未完成的任务的总数就会减少。
imglist = []
def main():
  global imglist
  url = "http://huaban.com/favorite/beauty/" # 要爬的网页地址
  html = getHtml(url)
  imglist = getUrl(html)
def main_1():
  global count
  threads = []
  count = 0
  queue = Queue.Queue()
  # 将所有任务加入队列
  for img in imglist:
    queue.put(img)
  # 多线程爬去图片
  for i in range(4):
    thread = getImg(queue, i)
    threads.append(thread)
  # 阻塞线程,直到线程执行完成
  for thread in threads:
    thread.join()
if __name__ == '__main__':
  main()
  t = timeit.Timer(main_1)
  print t.timeit(1)

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

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

def main_1():
  global count
  threads = []
  count = 0
  queue = Queue.Queue()
  # 将所有任务加入队列
  for img in imglist:
    queue.put(img)
  # 多线程爬去图片
  for i in range(1):
    thread = getImg(queue, i)
    threads.append(thread)
  # 阻塞线程,直到线程执行完成
  for thread in threads:
    thread.join()

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

Python多线程原理与用法实例剖析

再来看一个:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
import timeit
def countdown(n):
  while n > 0:
    n -= 1
def task1():
  COUNT = 100000000
  thread1 = threading.Thread(target=countdown, args=(COUNT,))
  thread1.start()
  thread1.join()
def task2():
  COUNT = 100000000
  thread1 = threading.Thread(target=countdown, args=(COUNT // 2,))
  thread2 = threading.Thread(target=countdown, args=(COUNT // 2,))
  thread1.start()
  thread2.start()
  thread1.join()
  thread2.join()
if __name__ == '__main__':
  t1 = timeit.Timer(task1)
  print "countdown in one thread ", t1.timeit(1)
  t2 = timeit.Timer(task2)
  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密集型任务(计算嘛)

Python多线程原理与用法实例剖析

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

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

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
使用Python判断质数(素数)的简单方法讲解
May 05 Python
Python新手们容易犯的几个错误总结
Apr 01 Python
浅谈python连续赋值可能引发的错误
Nov 10 Python
PyCharm鼠标右键不显示Run unittest的解决方法
Nov 30 Python
对python制作自己的数据集实例讲解
Dec 12 Python
利用Django模版生成树状结构实例代码
May 19 Python
Flask框架工厂函数用法实例分析
May 25 Python
Python语法分析之字符串格式化
Jun 13 Python
pandas分区间,算频率的实例
Jul 04 Python
vscode调试django项目的方法
Aug 06 Python
pandas apply使用多列计算生成新的列实现示例
Feb 24 Python
python利用while求100内的整数和方式
Nov 07 Python
python解析含有重复key的json方法
Jan 22 #Python
Python设计模式之简单工厂模式实例详解
Jan 22 #Python
对python字典过滤条件的实例详解
Jan 22 #Python
python实现淘宝秒杀脚本
Jun 23 #Python
python实现网页自动签到功能
Jan 21 #Python
python实现桌面壁纸切换功能
Jan 21 #Python
在Python中通过getattr获取对象引用的方法
Jan 21 #Python
You might like
PHP url 加密解密函数代码
2011/08/26 PHP
PHP JS Ip地址及域名格式检测代码
2013/09/27 PHP
Zend Framework分发器用法示例
2016/12/11 PHP
在Javascript里访问SharePoint列表数据的实现方法
2011/05/22 Javascript
自动刷新网页,自动刷新当前页面,JS调用
2013/06/24 Javascript
jQuery中noConflict()用法实例分析
2015/02/08 Javascript
NodeJS使用formidable实现文件上传
2016/10/27 NodeJs
详细讲解vue2+vuex+axios
2017/05/27 Javascript
Nodejs实现多房间简易聊天室功能
2017/06/20 NodeJs
基于jquery.page.js实现分页效果
2018/01/01 jQuery
解决vue多个路由共用一个页面的问题
2018/03/12 Javascript
浅谈JavaScript 代码整洁之道
2018/10/23 Javascript
如何自定义微信小程序tabbar上边框的颜色
2019/07/09 Javascript
微信小程序实现锚点功能
2019/11/20 Javascript
jquery更改元素属性attr()方法操作示例
2020/05/22 jQuery
JavaScript实现刮刮乐效果
2020/11/01 Javascript
[01:35:13]DOTA2-DPC中国联赛 正赛 DLG vs PHOENIX BO3 第一场 1月18日
2021/03/11 DOTA
Python实现获取操作系统版本信息方法
2015/04/08 Python
Python中关于使用模块的基础知识
2015/05/24 Python
Python基于DES算法加密解密实例
2015/06/03 Python
python使用clear方法清除字典内全部数据实例
2015/07/11 Python
Python首次安装后运行报错(0xc000007b)的解决方法
2016/10/18 Python
详解Python 爬取13个旅游城市,告诉你五一大家最爱去哪玩?
2019/05/07 Python
Python绘制堆叠柱状图的实例
2019/07/09 Python
Python HTMLTestRunner测试报告view按钮失效解决方案
2020/05/25 Python
python 绘制场景热力图的示例
2020/09/23 Python
css3实现的下拉菜单效果示例
2014/01/22 HTML / CSS
Html5原生拖拽相关事件简介以及基础实现
2020/11/19 HTML / CSS
农村婚礼证婚词
2014/01/08 职场文书
酒吧创业计划书
2014/01/18 职场文书
2014年三八妇女节活动方案
2014/02/28 职场文书
空气环保标语
2014/06/12 职场文书
公务员群众路线心得体会
2014/11/03 职场文书
护士年终考核评语
2014/12/31 职场文书
机关干部纪律作风整顿心得体会
2016/01/23 职场文书
Java Redisson多策略注解限流
2022/09/23 Java/Android