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遍历指定文件及文件夹的方法
May 09 Python
pytorch + visdom CNN处理自建图片数据集的方法
Jun 04 Python
对python中数据集划分函数StratifiedShuffleSplit的使用详解
Dec 11 Python
pandas的排序和排名的具体使用
Jul 31 Python
python中的反斜杠问题深入讲解
Aug 12 Python
Python 等分切分数据及规则命名的实例代码
Aug 16 Python
Python使用QQ邮箱发送邮件报错smtplib.SMTPAuthenticationError
Dec 20 Python
python爬虫开发之Request模块从安装到详细使用方法与实例全解
Mar 09 Python
Python绘图之柱形图绘制详解
Jul 28 Python
Python内置函数property()如何使用
Sep 01 Python
详解Python之Scrapy爬虫教程NBA球员数据存放到Mysql数据库
Jan 24 Python
pytorch 运行一段时间后出现GPU OOM的问题
Jun 02 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之第四天
2006/10/09 PHP
用php获取本周,上周,本月,上月,本季度日期的代码
2009/08/05 PHP
php提示Call-time pass-by-reference has been deprecated in的解决方法[已测]
2012/05/06 PHP
微信公众平台开发之天气预报功能
2015/08/31 PHP
关于PHP通用返回值设置方法
2017/03/31 PHP
jQuery 性能优化指南(3)
2009/05/21 Javascript
js 实现复制到粘贴板的功能代码
2010/05/13 Javascript
Jquery ajax传递复杂参数给WebService的实现代码
2011/08/08 Javascript
jquery获取div距离窗口和父级dv的距离示例
2013/10/10 Javascript
JavaScript实现文字跟随鼠标特效
2015/08/06 Javascript
js动态生成Html元素实现Post操作(createElement)
2015/09/14 Javascript
Angular.js项目中使用gulp实现自动化构建以及压缩打包详解
2017/07/19 Javascript
用Node提供静态文件服务的方法
2018/07/06 Javascript
JS实现处理时间,年月日,星期的公共方法示例
2019/05/31 Javascript
Layui点击图片弹框预览的实现方法
2019/09/16 Javascript
layui 图片上传+表单提交+ Spring MVC的实例
2019/09/21 Javascript
Vue 使用beforeEach实现登录状态检查功能
2019/10/31 Javascript
[47:45]DOTA2-DPC中国联赛 正赛 Phoenix vs Dragon BO3 第一场 2月26日
2021/03/11 DOTA
python 循环while和for in简单实例
2016/08/16 Python
pyqt5自定义信号实例解析
2018/01/31 Python
python批量修改文件夹及其子文件夹下的文件内容
2019/03/15 Python
python画图的函数用法以及技巧
2019/06/28 Python
Python学习笔记之集合的概念和简单使用示例
2019/08/22 Python
使用OpenCV实现仿射变换—平移功能
2019/08/29 Python
django-xadmin根据当前登录用户动态设置表单字段默认值方式
2020/03/13 Python
Python Django路径配置实现过程解析
2020/11/05 Python
G-Form护具官方网站:美国运动保护装备
2019/09/04 全球购物
大学生职业生涯设计书
2014/01/02 职场文书
食堂采购员岗位职责
2014/03/17 职场文书
语文教研活动总结
2014/07/02 职场文书
正风肃纪剖析材料
2014/09/30 职场文书
介绍信如何写
2015/01/31 职场文书
教师党员个人自我评价
2015/03/04 职场文书
工程项目合作意向书
2015/05/08 职场文书
特种设备安全管理制度
2015/08/06 职场文书
html,css,javascript是怎样变成页面的
2023/05/07 HTML / CSS