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排序搜索基本算法之堆排序实例详解
Dec 08 Python
Python实现的多进程和多线程功能示例
May 29 Python
树莓派使用USB摄像头和motion实现监控
Jun 22 Python
Python实现 PS 图像调整中的亮度调整
Jun 28 Python
python用win32gui遍历窗口并设置窗口位置的方法
Jul 26 Python
Python解决pip install时出现的Could not fetch URL问题
Aug 01 Python
python SVD压缩图像的实现代码
Nov 05 Python
Python实现隐马尔可夫模型的前向后向算法的示例代码
Dec 31 Python
Python多进程multiprocessing、进程池用法实例分析
Mar 24 Python
windows下的pycharm安装及其设置中文菜单
Apr 23 Python
使用Python3 poplib模块删除服务器多天前的邮件实现代码
Apr 24 Python
python Scrapy框架原理解析
Jan 04 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下常用正则表达式整理
2010/10/26 PHP
深入PHP5中的魔术方法详解
2013/06/17 PHP
typecho插件编写教程(二):写一个新插件
2015/05/28 PHP
PHP利用APC模块实现大文件上传进度条的方法
2015/10/29 PHP
PHP转换文本框内容为HTML格式的方法
2016/07/20 PHP
thinkPHP框架对接支付宝即时到账接口回调操作示例
2016/11/14 PHP
PHP的中使用非缓冲模式查询数据库的方法
2017/02/05 PHP
php基于Redis消息队列实现的消息推送的方法
2018/11/28 PHP
JS控制表格隔行变色
2006/06/26 Javascript
常用js脚本
2006/12/03 Javascript
javascript 复杂的嵌套环境中输出单引号和双引号
2009/05/26 Javascript
比较简单的异步加载JS文件的代码
2009/07/18 Javascript
IE 上下滚动展示模仿Marquee机制
2009/12/20 Javascript
Javascript中的变量使用说明
2010/05/18 Javascript
引用外部js乱码问题分析及解决方案
2013/04/12 Javascript
学习javascript的闭包,原型,和匿名函数之旅
2015/10/18 Javascript
Javascript页面跳转常见实现方式汇总
2015/11/28 Javascript
微信小程序 wxapp内容组件 progress详细介绍
2016/10/31 Javascript
AngularJS实现表单验证功能
2017/01/09 Javascript
微信小程序中吸底按钮适配iPhone X方案
2017/11/29 Javascript
解决axios会发送两次请求,有个OPTIONS请求的问题
2018/10/25 Javascript
简单了解vue中的v-if和v-show的区别
2019/10/08 Javascript
vue-next/runtime-core 源码阅读指南详解
2019/10/25 Javascript
vue 中this.$set 动态绑定数据的案例讲解
2021/01/29 Vue.js
详解Python编程中基本的数学计算使用
2016/02/04 Python
python实现寻找最长回文子序列的方法
2018/06/02 Python
python+selenium实现自动化百度搜索关键词
2019/06/03 Python
Python图像处理PIL各模块详细介绍(推荐)
2019/07/17 Python
深入了解Django中间件及其方法
2019/07/26 Python
opencv之为图像添加边界的方法示例
2019/12/26 Python
Python openpyxl模块原理及用法解析
2020/01/19 Python
TensorFlow 显存使用机制详解
2020/02/03 Python
基于Django集成CAS实现流程详解
2020/11/28 Python
2014年办公室工作总结范文
2014/11/12 职场文书
招标保密承诺书
2015/01/20 职场文书
Spring Security动态权限的实现方法详解
2022/06/16 Java/Android