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 相关文章推荐
对Tensorflow中的矩阵运算函数详解
Jul 27 Python
python 输入一个数n,求n个数求乘或求和的实例
Nov 13 Python
Selenium chrome配置代理Python版的方法
Nov 29 Python
python+selenium实现QQ邮箱自动发送功能
Jan 23 Python
对python中if语句的真假判断实例详解
Feb 18 Python
Python中如何使用if语句处理列表实例代码
Feb 24 Python
对python3 sort sorted 函数的应用详解
Jun 27 Python
Django文件存储 自己定制存储系统解析
Aug 02 Python
Python实现计算长方形面积(带参数函数demo)
Jan 18 Python
Python 多进程、多线程效率对比
Nov 19 Python
pytorch中[..., 0]的用法说明
May 20 Python
Django+Celery实现定时任务的示例
Jun 23 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中Array2xml类实现数组转化成XML实例
2014/12/08 PHP
在Laravel 中实现是否关注的示例
2019/10/22 PHP
javascript一个无懈可击的实例化XMLHttpRequest的方法
2010/10/13 Javascript
IE的有条件注释判定IE版本详解(附实例代码)
2012/01/04 Javascript
jquery 添加节点的几种方法介绍
2013/09/04 Javascript
javascript通过获取html标签属性class实现多选项卡的方法
2015/07/27 Javascript
javascript函数自动执行常用方法汇总
2016/03/28 Javascript
基于BootStrap Metronic开发框架经验小结【九】实现Web页面内容的打印预览和保存操作
2016/05/12 Javascript
js实现select选择框效果及美化
2016/08/19 Javascript
Bootstrap下拉菜单Dropdowns的实现代码
2017/03/17 Javascript
WebSocket实现简单客服聊天系统
2017/05/12 Javascript
nodejs 生成和导出 word的实例代码
2018/07/31 NodeJs
vue axios基于常见业务场景的二次封装的实现
2018/09/21 Javascript
Vue项目自动转换 px 为 rem的实现方法
2018/10/29 Javascript
原生JS实现列表内容自动向上滚动效果
2019/05/22 Javascript
layui关闭层级、简单监听的实例
2019/09/06 Javascript
JS可断点续传文件上传实现代码解析
2020/07/30 Javascript
[15:58]DOTA2国际邀请赛采访专栏:Tongfu.Sansheng&KingJ,DK.rOtk
2013/08/08 DOTA
[01:28:24]NAVI vs VG Supermajor 败者组 BO3 第三场 6.5
2018/06/06 DOTA
Python中pip安装非PyPI官网第三方库的方法
2015/06/02 Python
Python中模块string.py详解
2017/03/12 Python
Python 文件操作的详解及实例
2017/09/18 Python
Python 3.x 判断 dict 是否包含某键值的实例讲解
2018/07/06 Python
Python参数解析模块sys、getopt、argparse使用与对比分析
2019/04/02 Python
树莓派实现移动拍照
2019/06/22 Python
用python解压分析jar包实例
2020/01/16 Python
Python Handler处理器和自定义Opener原理详解
2020/03/05 Python
python爬虫泛滥的解决方法详解
2020/11/25 Python
python绘图模块之利用turtle画图
2021/02/12 Python
2019史上最全Database工程师题库
2015/12/06 面试题
取保候审保证书
2014/04/30 职场文书
火灾现场处置方案
2014/05/28 职场文书
会议新闻稿
2015/07/17 职场文书
《刺客之王:C罗全景传记》:时代从来不会亏待手艺人
2019/11/28 职场文书
十大冰系宝可梦排名,颜值最高的阿罗拉九尾,第三使用率第一
2022/03/18 日漫
世界十大评分最高的动漫,CLANNAD上榜,第八赚足人们眼泪
2022/03/18 日漫