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 相关文章推荐
Python2中的raw_input() 与 input()
Jun 12 Python
Python 12306抢火车票脚本 Python京东抢手机脚本
Feb 06 Python
Python2.7 实现引入自己写的类方法
Apr 29 Python
让代码变得更易维护的7个Python库
Oct 09 Python
python最小生成树kruskal与prim算法详解
Jan 17 Python
Python 类方法和实例方法(@classmethod),静态方法(@staticmethod)原理与用法分析
Sep 20 Python
Python单元测试模块doctest的具体使用
Feb 10 Python
python 统计list中各个元素出现的次数的几种方法
Feb 20 Python
如何判断pytorch是否支持GPU加速
Jun 01 Python
Python实现学生管理系统(面向对象版)
Jun 24 Python
Python 的 sum() Pythonic 的求和方法详细
Oct 16 Python
Python Matplotlib库实现画局部图
Nov 17 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
服务器变量 $_SERVER 的深入解析
2013/07/02 PHP
ThinkPHP中使用ajax接收json数据的方法
2014/12/18 PHP
php中使用GD库做验证码
2016/03/31 PHP
PHP命令行执行整合pathinfo模拟定时任务实例
2016/08/12 PHP
Jquery从头学起第四讲 jquery入门教程
2010/08/01 Javascript
用js实现trim()的解决办法
2013/04/16 Javascript
setInterval与clearInterval的使用示例代码
2014/01/28 Javascript
js重写alert控件(适合学习js的新手朋友)
2014/08/24 Javascript
js实现鼠标经过时图片滚动停止的方法
2015/02/16 Javascript
jQuery实现点击图片翻页展示效果的方法
2015/02/16 Javascript
jQuery获取父元素节点、子元素节点及兄弟元素节点的方法
2016/04/14 Javascript
node.js入门学习之url模块
2017/02/25 Javascript
js中编码函数:escape,encodeURI与encodeURIComponent详解
2017/03/21 Javascript
微信扫码支付零云插件版实例详解
2017/04/26 Javascript
解决JSON.stringify()自动将中文转译成unicode的问题
2018/01/05 Javascript
微信小程序wx:for和wx:for-item的用法详解
2018/04/01 Javascript
vue实现点击隐藏与显示实例分享
2019/02/13 Javascript
layui实现鼠标移动到单元格上显示数据的方法
2019/09/11 Javascript
vue element-ui读取pdf文件的方法
2019/11/26 Javascript
微信小程序吸底区域适配iPhoneX的实现
2020/04/09 Javascript
[00:57]深扒TI7聊天轮盘语音出处5
2017/05/11 DOTA
Windows下安装python MySQLdb遇到的问题及解决方法
2017/03/16 Python
python 矩阵增加一行或一列的实例
2018/04/04 Python
Python2与Python3的区别实例分析
2019/04/11 Python
深入浅析Python 中 is 语法带来的误解
2019/05/07 Python
python requests指定出口ip的例子
2019/07/25 Python
python opencv将图片转为灰度图的方法示例
2019/07/31 Python
python实现输入的数据在地图上生成热力图效果
2019/12/06 Python
俄罗斯旅游网站:Tripadvisor俄罗斯
2017/03/21 全球购物
岗位廉洁从业承诺书
2014/03/28 职场文书
厨师个人自我鉴定范文
2014/04/19 职场文书
设计大赛策划方案
2014/06/13 职场文书
个人销售励志奋斗口号
2019/12/05 职场文书
oracle覆盖导入dmp文件的2种方法
2021/05/21 Oracle
解决mysql模糊查询索引失效问题的几种方法
2021/06/18 MySQL
python函数的两种嵌套方法使用
2022/04/02 Python