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 用户登录验证的小例子
Mar 06 Python
Python 检查数组元素是否存在类似PHP isset()方法
Oct 14 Python
python 函数传参之传值还是传引用的分析
Sep 07 Python
python逆向入门教程
Jan 15 Python
Python爬虫抓取代理IP并检验可用性的实例
May 07 Python
Python递归函数实例讲解
Feb 27 Python
pyqt5 实现 下拉菜单 + 打开文件的示例代码
Jun 20 Python
python将字母转化为数字实例方法
Oct 04 Python
Python类的动态绑定实现原理
Mar 21 Python
python小程序基于Jupyter实现天气查询的方法
Mar 27 Python
python 中关于pycharm选择运行环境的问题
Oct 31 Python
pycharm2021激活码使用教程(永久激活亲测可用)
Mar 30 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
用IE远程创建Mysql数据库的简易程序
2006/10/09 PHP
一个从别的网站抓取信息的例子(域名查询)
2006/10/09 PHP
php数组函数序列之array_sum() - 计算数组元素值之和
2011/10/29 PHP
PHP性能优化大全(php.ini)
2016/05/20 PHP
php 自定义错误日志实例详解
2016/11/12 PHP
js监听表单value的修改同步问题,跨浏览器支持
2009/12/31 Javascript
JavaScript获得url查询参数的方法
2015/07/02 Javascript
JS实现浏览器状态栏文字从右向左弹出效果代码
2015/10/27 Javascript
深入理解jquery中的事件与动画
2016/05/24 Javascript
JS中的hasOwnProperty()和isPrototypeOf()属性实例详解
2016/08/11 Javascript
js 创建对象 经典模式全面了解
2016/08/16 Javascript
AngularJS 应用身份认证的技巧总结
2016/11/07 Javascript
js实现下拉框效果(select)
2017/03/28 Javascript
ES6中Proxy代理用法实例浅析
2017/04/06 Javascript
easyui关于validatebox实现多重规则验证的方法(必看)
2017/04/12 Javascript
微信小程序之网络请求简单封装实例详解
2017/06/28 Javascript
vue实现表格增删改查效果的实例代码
2017/07/18 Javascript
Bootstrap table使用方法记录
2017/08/23 Javascript
js嵌套的数组扁平化:将多维数组变成一维数组以及push()与concat()区别的讲解
2019/01/19 Javascript
python实现跨excel的工作表sheet之间的复制方法
2018/05/03 Python
分享vim python缩进等一些配置
2018/07/02 Python
浅谈pytorch、cuda、python的版本对齐问题
2020/01/15 Python
python3检查字典传入函数键是否齐全的实例
2020/06/05 Python
关于python scrapy中添加cookie踩坑记录
2020/11/17 Python
pycharm实现猜数游戏
2020/12/07 Python
html5页面结构_动力节点Java学院整理
2017/07/10 HTML / CSS
华为旗下电子商务平台:华为商城
2016/08/06 全球购物
Keds加拿大官网:购买帆布运动鞋和皮鞋
2019/09/26 全球购物
俄罗斯珠宝市场的领导者之一:Бронницкий ювелир
2019/10/02 全球购物
四川internet信息高速公路(C#)笔试题
2012/02/29 面试题
获奖的大学生创业计划书
2014/01/05 职场文书
《音乐之都维也纳》教学反思
2014/04/16 职场文书
旅游与环境专业求职信
2014/06/05 职场文书
2016入党积极分子党课培训心得体会
2016/01/06 职场文书
《吃水不忘挖井人》教学反思
2016/02/22 职场文书
动视暴雪取消疫苗禁令 让所有员工返回线下工作
2022/04/03 其他游戏