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中zip和unzip数据的方法
May 27 Python
Python实现简单的文件传输与MySQL备份的脚本分享
Jan 03 Python
使用Nginx+uWsgi实现Python的Django框架站点动静分离
Mar 21 Python
python实现简单socket通信的方法
Apr 19 Python
Python3.x对JSON的一些操作示例
Sep 01 Python
Python中的单行、多行、中文注释方法
Jul 19 Python
NumPy 基本切片和索引的具体使用方法
Apr 24 Python
django多文件上传,form提交,多对多外键保存的实例
Aug 06 Python
在python Numpy中求向量和矩阵的范数实例
Aug 26 Python
Python with语句和过程抽取思想
Dec 23 Python
Python中的全局变量如何理解
Jun 04 Python
python 如何做一个识别率百分百的OCR
May 29 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中stream(流)的用法
2014/03/25 PHP
使用ob系列函数实现PHP网站页面静态化
2014/08/13 PHP
jQuery EasyUI API 中文文档 - Form表单
2011/10/06 Javascript
jQuery 绑定事件到动态创建的元素上的方法实例
2013/08/18 Javascript
JSuggest自动匹配下拉框使用方法(示例代码)
2013/12/27 Javascript
基于JavaScript实现图片点击弹出窗口而不是保存
2016/02/06 Javascript
javascript 动态脚本添加的简单方法
2016/10/11 Javascript
jQuery简介_动力节点Java学院整理
2017/07/04 jQuery
利用node.js如何创建子进程详解
2017/12/09 Javascript
基于express中路由规则及获取请求参数的方法
2018/03/12 Javascript
详解小程序缓存插件(mrc)
2018/08/17 Javascript
uni-app之APP和小程序微信授权方法
2019/05/09 Javascript
vuex实现数据状态持久化
2019/11/11 Javascript
原生js实现自定义滚动条组件
2021/01/20 Javascript
[07:25]DOTA2-DPC中国联赛2月5日Recap集锦
2021/03/11 DOTA
python开发的小球完全弹性碰撞游戏代码
2013/10/15 Python
对python创建及引用动态变量名的示例讲解
2018/11/10 Python
Python OpenCV对本地视频文件进行分帧保存的实例
2019/01/08 Python
计算机二级python学习教程(1) 教大家如何学习python
2019/05/16 Python
基于python-opencv3的图像显示和保存操作
2019/06/27 Python
Python数据可视化实现正态分布(高斯分布)
2019/08/21 Python
Tory Burch英国官方网站:美国时尚生活品牌
2017/12/06 全球购物
加拿大建筑和装修专家:Reno-Depot
2017/12/21 全球购物
澳大利亚购买太阳镜和眼镜网站:Glamoureyes
2020/09/22 全球购物
速卖通欧盟:Aliexpress EU
2020/08/19 全球购物
客服专员岗位职责范本
2013/11/29 职场文书
大学生职业生涯规划书模板
2014/01/03 职场文书
新郎父亲婚宴答谢词
2014/01/11 职场文书
2014年迎新年联欢会活动策划方案
2014/02/26 职场文书
期末学生评语大全
2014/04/24 职场文书
拒绝黄毒毒宣传标语
2014/06/26 职场文书
幼儿教师师德师风自我剖析材料
2014/09/29 职场文书
2014年仓库工作总结
2014/11/20 职场文书
2015年三年级班主任工作总结
2015/05/21 职场文书
ORM模型框架操作mysql数据库的方法
2021/07/25 MySQL
解决IIS7下无法绑定https主机的问题
2022/04/29 Servers