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对小数进行除法运算的正确方法示例
Aug 25 Python
python进程类subprocess的一些操作方法例子
Nov 22 Python
django开发post接口简单案例,获取参数值的方法
Dec 11 Python
在Python中关于使用os模块遍历目录的实现方法
Jan 03 Python
Python 实现中值滤波、均值滤波的方法
Jan 09 Python
利用Python库Scapy解析pcap文件的方法
Jul 23 Python
树莓派安装OpenCV3完整过程的实现
Oct 10 Python
Python 脚本拉取 Docker 镜像问题
Nov 10 Python
Flask之pipenv虚拟环境的实现
Nov 26 Python
Django中的session用法详解
Mar 09 Python
Python持续监听文件变化代码实例
Jul 22 Python
python程序实现BTC(比特币)挖矿的完整代码
Jan 20 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
在WordPress中安装使用视频播放器插件Hana Flv Player
2016/01/04 PHP
php文件管理基本功能简单操作
2017/01/16 PHP
Laravel5.* 打印出执行的sql语句的方法
2017/07/24 PHP
PHP htmlentities()函数用法讲解
2019/02/25 PHP
jquery 检测元素是否存在的实例代码
2013/11/19 Javascript
JS判断是否长按某一键的方法
2016/03/02 Javascript
分享一个原生的JavaScript拖动方法
2016/09/25 Javascript
详解nodeJS之二进制buffer对象
2017/06/03 NodeJs
Vue动态组件实例解析
2017/08/20 Javascript
vue使用axios实现文件上传进度的实时更新详解
2017/12/20 Javascript
VSCode配置react开发环境的步骤
2017/12/27 Javascript
Nodejs中的JWT和Session的使用
2018/08/21 NodeJs
vue轻量级框架无法获取到vue对象解决方法
2019/05/12 Javascript
Vue 3.0 前瞻Vue Function API新特性体验
2019/08/12 Javascript
[01:00:30]完美世界DOTA2联赛循环赛 Inki vs Matador BO2第二场 10.31
2020/11/02 DOTA
PyCharm代码整体缩进,反向缩进的方法
2018/06/25 Python
win7+Python3.5下scrapy的安装方法
2018/07/31 Python
解决python线程卡死的问题
2019/02/18 Python
Django如何实现上传图片功能
2019/08/16 Python
Pytorch 实现权重初始化
2019/12/31 Python
pytorch数据预处理错误的解决
2020/02/20 Python
Python数据相关系数矩阵和热力图轻松实现教程
2020/06/16 Python
Python迭代器协议及for循环工作机制详解
2020/07/14 Python
Python 整行读取文本方法并去掉readlines换行\n操作
2020/09/03 Python
解决Python3.7.0 SSL低版本导致Pip无法使用问题
2020/09/03 Python
python tkinter的消息框模块(messagebox,simpledialog)
2020/11/07 Python
HTML5 canvas基本绘图之绘制矩形
2016/06/27 HTML / CSS
英国最大最好的无人机商店:Drones Direct
2019/07/12 全球购物
澳大利亚珠宝商:Shiels
2019/10/06 全球购物
印尼购物网站:iLOTTE
2019/10/16 全球购物
介绍一下SQL注入攻击的种类和防范手段
2012/02/18 面试题
医院办公室主任岗位职责
2015/04/01 职场文书
客户付款通知书
2015/04/23 职场文书
女方家长婚礼致辞
2015/07/27 职场文书
创业计划书之校园超市
2019/09/12 职场文书
JavaScript实现简单图片切换
2021/04/29 Javascript