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中optionParser模块的使用方法实例教程
Aug 29 Python
基于Python实现文件大小输出
Jan 11 Python
Python实现将数据库一键导出为Excel表格的实例
Dec 30 Python
python 读取txt,json和hdf5文件的实例
Jun 05 Python
python使用pygame模块实现坦克大战游戏
Mar 25 Python
python中pytest收集用例规则与运行指定用例详解
Jun 27 Python
python中hasattr()、getattr()、setattr()函数的使用
Aug 16 Python
Python如何读取文件中图片格式
Jan 13 Python
浅析python标准库中的glob
Mar 13 Python
Python Tornado批量上传图片并显示功能
Mar 26 Python
Python爬虫之Selenium多窗口切换的实现
Dec 04 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 iconv() : Detected an illegal character in input string
2010/12/05 PHP
PHP实现的英文名字全拼随机排号脚本
2014/07/04 PHP
PHP数组排序之sort、asort与ksort用法实例
2014/09/08 PHP
thinkphp中session和cookie无效的解决方法
2014/12/19 PHP
php生成年月日下载列表的方法
2015/04/24 PHP
ZF框架实现发送邮件的方法
2015/12/03 PHP
PHP微信API接口类
2016/08/22 PHP
php使用CutyCapt实现网页截图保存的方法
2016/10/03 PHP
PHP ADODB生成HTML表格函数rs2html功能【附错误处理函数用法】
2018/05/29 PHP
PHP实现文件上传操作和封装
2020/03/04 PHP
50款非常棒的 jQuery 插件分享
2012/03/29 Javascript
javascript中日期转换成时间戳的小例子
2013/03/21 Javascript
解析Jquery取得iframe中元素的几种方法
2013/07/04 Javascript
总结Javascript中数组各种去重的方法
2016/10/04 Javascript
jQuery将表单序列化成一个Object对象的实例
2016/11/29 Javascript
JS限定手机版中图片大小随分辨率自动调整的方法
2016/12/05 Javascript
nodejs操作mysql实现增删改查的实例
2017/05/28 NodeJs
Vue.js移动端左滑删除组件的实现代码
2017/09/08 Javascript
详解给Vue2路由导航钩子和axios拦截器做个封装
2018/04/10 Javascript
CSS3 动画卡顿性能优化的完美解决方案
2018/09/20 Javascript
vue解决使用$http获取数据时报错的问题
2019/10/30 Javascript
[06:07]刀塔密之二:攻之吾命受之吾幸
2014/07/03 DOTA
python中合并两个文本文件并按照姓名首字母排序的例子
2014/04/25 Python
django-rest-swagger的优化使用方法
2019/08/29 Python
给我一面国旗 python帮你实现
2019/09/30 Python
tensorflow 获取checkpoint中的变量列表实例
2020/02/11 Python
如何用 Python 制作一个迷宫游戏
2021/02/25 Python
解决HTML5手机端页面缩放的问题
2017/10/27 HTML / CSS
日本快乐生活方式购物网站:Shop Japan
2018/07/17 全球购物
党支部书记四风问题整改措施
2014/09/24 职场文书
单方离婚协议书范本(2014版)
2014/09/30 职场文书
2014年学校团委工作总结
2014/12/20 职场文书
全陪导游词
2015/02/04 职场文书
2015选调生工作总结
2015/07/24 职场文书
教你用eclipse连接mysql数据库
2021/04/22 MySQL
go:垃圾回收GC触发条件详解
2021/04/24 Golang