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通过wxPython打开一个音频文件并播放的方法
Mar 25 Python
浅谈Python 中整型对象的存储问题
May 16 Python
python select.select模块通信全过程解析
Sep 20 Python
Django中反向生成models.py的实例讲解
May 30 Python
mvc框架打造笔记之wsgi协议的优缺点以及接口实现
Aug 01 Python
python字符串循环左移
Mar 08 Python
python判断所输入的任意一个正整数是否为素数的两种方法
Jun 27 Python
python实现基于朴素贝叶斯的垃圾分类算法
Jul 09 Python
Django REST framework内置路由用法
Jul 26 Python
Python使用openpyxl复制整张sheet
Mar 24 Python
Django项目如何获得SSL证书与配置HTTPS
Apr 30 Python
Python趣味实战之手把手教你实现举牌小人生成器
Jun 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
推荐文章系统(一)
2006/10/09 PHP
一步一步学习PHP(1) php开发环境配置
2010/02/15 PHP
在Windows系统上安装PHP运行环境文字教程
2010/07/19 PHP
jQuery入门问答 整理的几个常见的初学者问题
2010/02/22 Javascript
TreeView 用法(有代码)(asp.net)
2011/07/15 Javascript
JavaScript调用堆栈及setTimeout使用方法深入剖析
2013/02/16 Javascript
Javascript写入txt和读取txt文件示例
2014/02/12 Javascript
js+css实现超简洁的二级下拉菜单效果代码
2015/09/07 Javascript
AngualrJS中的Directive制作一个菜单
2016/01/26 Javascript
JavaScript的函数式编程基础指南
2016/03/19 Javascript
JS DOM实现鼠标滑动图片效果
2020/09/17 Javascript
js小数计算小数点后显示多位小数的实现方法
2016/05/30 Javascript
Vue.js Ajax动态参数与列表显示实现方法
2016/10/20 Javascript
AngularJS指令用法详解
2016/11/02 Javascript
微信小程序 常用工具类详解及实例
2017/02/15 Javascript
nodejs学习笔记之路由
2017/03/27 NodeJs
js遍历获取表格内数据的方法(必看)
2017/04/06 Javascript
NodeJs的fs读写删除移动监听
2017/04/28 NodeJs
react系列从零开始_简单谈谈react
2017/07/06 Javascript
angular1配合gulp和bower的使用教程
2018/01/19 Javascript
浅谈webpack 自动刷新与解析
2018/04/09 Javascript
vue使用jsonp抓取qq音乐数据的方法
2018/06/21 Javascript
详解React之key的使用和实践
2018/09/29 Javascript
转换layUI的数据表格中的日期格式方法
2019/09/19 Javascript
Nuxt pages下不同的页面对应layout下的页面布局操作
2020/11/05 Javascript
Vue基本指令实例图文讲解
2021/02/25 Vue.js
Python标准库之collections包的使用教程
2017/04/27 Python
解决Python内层for循环如何break出外层的循环的问题
2019/06/24 Python
python实现删除列表中某个元素的3种方法
2020/01/15 Python
Revolution Beauty美国官网:英国知名化妆品网站
2018/07/23 全球购物
简单介绍Object类的功能、常用方法
2013/10/02 面试题
毕业生找工作推荐信
2013/11/21 职场文书
艺术学院毕业生求职信
2014/07/09 职场文书
总经理检讨书
2014/09/15 职场文书
群众路线教育实践活动总结
2014/10/30 职场文书
二年级数学教学反思
2016/02/16 职场文书