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 21 Python
python动态加载包的方法小结
Apr 18 Python
Pycharm在创建py文件时,自动添加文件头注释的实例
May 07 Python
详解python 注释、变量、类型
Aug 10 Python
python实现公司年会抽奖程序
Jan 22 Python
Django rest framework jwt的使用方法详解
Aug 08 Python
关于ZeroMQ 三种模式python3实现方式
Dec 23 Python
PyTorch里面的torch.nn.Parameter()详解
Jan 03 Python
Python startswith()和endswith() 方法原理解析
Apr 28 Python
python使用pygame创建精灵Sprite
Apr 06 Python
pytorch 如何使用float64训练
May 24 Python
Python爬虫基础初探selenium
May 31 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 syntax error, unexpected $end 错误的一种原因及解决
2008/10/25 PHP
ThinkPHP框架获取最后一次执行SQL语句及变量调试简单操作示例
2018/06/13 PHP
ThinkPHP框架整合微信支付之刷卡模式图文详解
2019/04/10 PHP
基于jquery的使ListNav兼容中文首字拼音排序的实现代码
2011/07/10 Javascript
在页面上用action传递参数到后台出现乱码的解决方法
2013/12/31 Javascript
浅谈JavaScript数据类型
2015/03/03 Javascript
jQuery中通过ajax调用webservice传递数组参数的问题实例详解
2016/05/20 Javascript
在React项目中使用Eslint代码检查工具及常见问题
2018/10/10 Javascript
vue项目中在外部js文件中直接调用vue实例的方法比如说this
2019/04/28 Javascript
webpack + vue 打包生成公共配置文件(域名) 方便动态修改
2019/08/29 Javascript
基于Vue和Element-Ui搭建项目的方法
2019/09/06 Javascript
js和jquery判断数据类型的4种方法总结
2020/08/28 jQuery
Vue.js暴露方法给WebView的使用操作
2020/09/07 Javascript
vue 项目软键盘回车触发搜索事件
2020/09/09 Javascript
返回上一个url并刷新界面的js代码
2020/09/12 Javascript
Vue实现购物小球抛物线的方法实例
2020/11/22 Vue.js
在Python的Django框架中实现Hacker News的一些功能
2015/04/17 Python
使用Python来编写HTTP服务器的超级指南
2016/02/18 Python
Python操作Oracle数据库的简单方法和封装类实例
2018/05/07 Python
python 集合 并集、交集 Series list set 转换的实例
2018/05/29 Python
Python小进度条显示代码
2019/03/05 Python
python并发编程多进程 互斥锁原理解析
2019/08/20 Python
pymysql 插入数据 转义处理方式
2020/03/02 Python
动态设置django的model field的默认值操作步骤
2020/03/30 Python
python程序需要编译吗
2020/06/19 Python
Python selenium实现断言3种方法解析
2020/09/08 Python
波兰在线运动商店:YesSport
2020/07/23 全球购物
Made in Design意大利:现代家具、名家灯具和装饰
2020/10/27 全球购物
EMPHASIS艾斐诗官网:周生生旗下原创精品珠宝品牌
2020/12/17 全球购物
还款承诺书范文
2014/05/20 职场文书
2014年学校党建工作汇报材料
2014/11/02 职场文书
武侯祠导游词
2015/02/04 职场文书
调解协议书范本
2016/03/21 职场文书
MySQL系列之八 MySQL服务器变量
2021/07/02 MySQL
win10系统xps文件怎么打开?win10打开xps文件的两种操作方法
2022/07/23 数码科技
js 实现验证码输入框示例详解
2022/09/23 Javascript