线程学习基础(1):单线程爬虫和多线程爬虫的效率比照
线程学习基础:单线程爬虫和多线程爬虫的效率比照
- 1. 并发线程的需求
- 2. 线程提速方法
- 3. 如何选择并发编程的三种方式
- 3.1 什么是CPU密集型计算、IO密集型计算?
- 3.1.1 CPU密集型(CPU-bound)
- 3.1.2 IO密集型(IO-bound)
- 3.2 多线程Thread、多进程Process和多协程Coroutine对比
- 3.2.1 多线程Thread(threading)
- 3.2.2 多进程Process(multiprocessing)
- 3.2.3 多协程 Coroutine(asyncio)
- 3.3 怎样根据任务选择对应技术?
- 4. Python程序运行为何慢?
- 4.1 Python速度慢的两大原因
- 4.2 GIL是什么?
- 4.3 为什么有GIL这个东西?
- 4.4 怎样规避GIL带来的限制?
- 5. 多线程使用Python
- 5.1 Python创建多线程的方法
- 5.2 改写爬虫程序,变成多线程爬取
- 5.3 速度对比:单线程爬虫VS多线程爬虫
学了一段日子的爬虫,开始进入并发编程的学习中,两三天内,对线程的理解有了一定的进步。特别是在B站看到个别大佬的讲解,如获至宝,做笔记在这里,以方便后面复习使用。
1. 并发线程的需求
为什么引入并发线程呢?
- 一个网络爬虫,按顺序爬取花了1小时,采用并发下载减少到20分钟;
- 一个APP应用,优化前每次打开页面需要3秒,采用异步并发提升到每次200毫秒;
引入并发,就是为了提升程序运行速度。
学习并掌握并发编程,是高级别+高薪资程序员的必备能力
2. 线程提速方法
- 多线程:threading,利用CPU和IO可以同时执行的原理,让CP不再干巴巴等IO完成
- 多进程:multiprocessiong,利用多核CPU的能力,真正的并行执行任务
- 异步IO:asyncio,在单线程利用CPU和IO同时执行的原理,实现函数异步执行
具体实现的时候,就有如下模块和方法
- 使用Lock对资源加锁,防止冲突访问
- 使用Queue实现不同线程/进程之间的数据通信,实现生产者-消费者模式
- 使用线程池Pool/进程池Pool,简化线程/进程的任务提交、等待结束、获取结果
- 使用subprocess启动外部程序的进程,并进行输入输出交互
3. 如何选择并发编程的三种方式
- 并发编程的三种方式——多线程Thread、多进程Process和多协程Coroutine
3.1 什么是CPU密集型计算、IO密集型计算?
3.1.1 CPU密集型(CPU-bound)
- CPU密集型也叫计算密集型,是指I/O在很短的时间就可以完成CPU需要大量的计算和处理,特点是CPU占用率相当高
- 例如:压缩解压缩、加密解密正则表达式搜索
3.1.2 IO密集型(IO-bound)
- lO密集型指的是系统运作大部分的状况是CPU在等I/O(硬盘/内存)的读/写操作,CPU占用率仍然较低
- 例如:文件处理程序、网络爬虫程序、读写数据库程序
3.2 多线程Thread、多进程Process和多协程Coroutine对比
3.2.1 多线程Thread(threading)
- 优点:相比进程,更轻量级占用资源少
- 缺点:
- 相比讲程:多线程只能并发执行,不能利用多CPU(GIL)
- 相比协程:启动数目有限制,占用内存资源,有线程切换开销
- 适用于:IO密集型计算、同时运行的任务数自要求不多
3.2.2 多进程Process(multiprocessing)
- 优点:可以利用多核CPU并行运算
- 缺点:占用资源最多、可启动数目比线程少
- 适用于:CPU密集型计算
3.2.3 多协程 Coroutine(asyncio)
- 优点:内存开销最少、启动协程数量最多
- 缺点:支持的库有限制(aionttp vs requests、代码实现复杂
- 适用于:IO密集型计算、需要超多任务运行、但有现成库支持的场景
3.3 怎样根据任务选择对应技术?
- 如图展示。
4. Python程序运行为何慢?
- 头号嫌疑犯——全局解释器锁GIL
4.1 Python速度慢的两大原因
- 相比C/C++/Java,Python甚至比C++慢100~200倍
- 各大公司的推荐引擎、搜索引擎、存储引擎等底层都用C/C++
- 两大大原因
- 动态类型语言,边解释边执行
- GIL无法利用多核CPU并发执行
4.2 GIL是什么?
- 全局解释器锁(英语: GlobalInterpreter Lock,缩写GIL)
- 是计算机程序设计语言解释器用于同步线程的一种机制,它使得任何时刻仅有一个线程在执行。即便在多核心处理器上,使用 GIL的解释器也只允许同一时间执行一个线程。
- 由于GIL的存在,即使电脑有多核CPU,单个时刻也只能使用1个,相比并发加速的C++、Java慢
4.3 为什么有GIL这个东西?
- 简而言之: Python设计初期,为了规避并发问题引入了GIL,现在想去除却去不掉了!
- 为了解决多线程之间数据完整性和状态同步问题,Python中对象的管理,是使用引用计数器进行的,引用数为0则释放对象。
- 以下图为例:
- 这样看来,GIL确实有好处:简化了Python对共享资源的管理。
4.4 怎样规避GIL带来的限制?
- 1、多线程 threading 机制依然是有用的,用于IO密集型计算。因为在 I/0 (read,write,send,recv,etc.)期间,线程会释放GIL,实现CPU和IO的并行因此多线程用于IO密集型计算依然可以大幅提升速度。但是多线程用于CPU密集型计算时,只会更加拖慢速度。
- 2、使用multiprocessing 的多进程机制实现并行计算、利用多核CPU优势为了应对GIL的问题,Python提供了multiprocessing。
5. 多线程使用Python
5.1 Python创建多线程的方法
5.2 改写爬虫程序,变成多线程爬取
- 写一个普通的爬虫程序
import requestsurls = [f"https://www.cnblogs.com/#p{page}"for page in range(1,51)
]def draw(url):r = requests.get(url) print(url, len(r.text))print(r.text)draw(urls[0])
- 导入requests模块,定义一个要爬取的地址列表,再定义一个爬虫函数,往函数里面代入参数运行。
- 运行结果如图。
- 上面只是爬取了一个当前的网页页面,字数为70366。
- 再看一个多线程式的爬虫程序。
import threading
import time
import requestsurls = [f"https://www.cnblogs.com/#p{page}"for page in range(1,51)
]def draw(url):r = requests.get(url)print(url, len(r.text))def single_thread():print("single_thread begin")for url in urls:draw(url)print("single_thread end")def multi_thread():print("multi_thread begin")threads = []for url in urls:threads.append(threading.Thread(target=draw, args=(url,), end=""))print(len(threads))for thread in threads:thread.start()# thread.join() # 如果join方法加在这里,又成了单线程的了for thread in threads:thread.join()print("multi_thread end")if __name__ == "__main__":# single_threadstart = time.time()single_thread()end = time.time()print("single thread cost:", end - start, "seconds")singleTime = end - start# multi_threadstart = time.time()multi_thread()end = time.time()print("multi thread cost:", end - start, "seconds")multiTime = end - startprint(str(singleTime / multiTime) + 'times')
- 上面代码,是爬取了50页的网页页面。
- 开始,还是先定义爬取的函数draw,然后定义一个单线程的函数,再定义一个多线程的函数。
- 为了方便截图,我在draw函数里面的打印参数里面加了去掉换行符的代码。
- 运行结果如图。
5.3 速度对比:单线程爬虫VS多线程爬虫
- 上面主程序中,为了对比单线程爬虫VS多线程爬虫的速度,定义了开始时间和结束时间的变量。
- 然后分别对单线程爬虫和多线程爬虫运行时间进行对比,发现效率大大提高。速度差了十几倍。
- 那么,爬取成千成万甚至几十G的数据,就更显得多线程的威力了。
线程学习基础(1):单线程爬虫和多线程爬虫的效率比照相关推荐
- 数据分析与爬虫实战视频——学习笔记(二)(千图网图片爬虫、fiddler抓包分析、腾讯视频评论爬虫、多线程爬虫(糗百))
网址:[数据挖掘]2019年最新python3 数据分析与数据爬虫实战 https://www.bilibili.com/video/av22571713/?p=26 第三周第二节课 1抓包分析实战 ...
- java多线程爬虫_Java 多线程爬虫及分布式爬虫架构
在这个时间就是金钱的年代,不可能给你时间去慢慢的采集,所以单线程爬虫程序是行不通的,我们需要将单线程改成多线程的模式,来提升采集效率和提高计算机利用率.维护待采集的 URL多线程爬虫程序就不能像单线程 ...
- python多线程爬虫框架_普通爬虫vs多线程爬虫vs框架爬虫,Python爬对比
前言 本文的文字及图片过滤网络,可以学习,交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. 基本开发环境 Python 3.6 皮查姆 目标网页分析 网站就选择发表情这个网站吧 网站是静 ...
- 4.1-python爬虫之多线程爬虫
系列文章目录 python爬虫目录 文章目录 系列文章目录 前言 一.多线程介绍 二.threading模块介绍 1.查看线程数 2.查看当前线程的名字 3.继承自threading.Thread类 ...
- python_爬虫 12 多线程爬虫
目录 多线程爬虫 一.多线程介绍: 二.threading模块介绍: 1.查看线程数: 2.查看当前线程的名字: 3.继承自threading.Thread类: 4.多线程共享全局变量的问题: 5.锁 ...
- Python爬虫——Python多线程爬虫详解
网络爬虫程序是一种 IO 密集型程序,程序中涉及了很多网络 IO 以及本地磁盘 IO 操作,这些都会消耗大量的时间,从而降低程序的执行效率,而 Python 提供的多线程能够在一定程度上提升 IO 密 ...
- java5个线程_java基础thread——java5之后的多线程(浅尝辄止)
承上启下 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock. 一.JD ...
- Python3 单线程爬虫 和 多线程爬虫 下载某站 古风头像,短短几分钟就3000多张
大家好我是宋哈哈,今天也是偶然和一位同事聊起关于爬虫的事情,然后发了我一个代码,是爬去古风头像的一个爬虫代码.他的爬虫代码是用在教学生用的,只是简单的爬取了当前页的古风头像,我接到接手后,我想在基础上 ...
- python3线程池爬虫_python3多线程爬虫中如何变量?
我们可以把待处理的程序看成一批需要配送的包裹,包裹在不同的货架上摆放.单人整理会比几个人一起摆放要慢的多.同样在计算机处理中,单凭借一个程序打开运行是远远不够用的,我们需要同时处理多个事物,所以多线程 ...
最新文章
- CTF web题总结--http header 修改、cookie注入
- XCode4 实践HelloWorld
- 函数的递归调用(专题)
- OutLook2016修改注册表迁移.ost文件数据
- 【HihoCoder - 1550】顺序三元组(思维)
- JAVA中List与Array之间互换
- 【正在完善】高级CSS特效解析其示范案例
- 全球及中国差旅费管理系统行业趋势分析与投资前景建议研究报告2022-2028年版
- 写一个上班看股票的小软件
- 软件测试加油站ic卡管理系统,加油站IC卡管理系统,加油机IC卡管理系统,加油站自助加油机功能介绍...
- CREO:CREO软件的简介、安装(七大步骤)、学习路线大全(CREO软件各模块界面解释—菜单栏快速栏工作区、草绘/零件/工程图/装配设计讲解)、案例应用(几十个案例)之详细攻略
- 常用的台式计算机,台式电脑常见简单故障排除
- phpspider 的简单使用
- 使用Swiss-Prot根据同源基因进行注释
- python123星号直角三角形_Python123:星号三角形、凯撒密码
- DhtmlxGrid第一次接触,jsp页面
- WIFI基础知识-2.4GZH的信号为什么比5GHZ的信号好
- java/php/net/python教学评价系统设计
- 微访谈:引爆微博舆论爆发的导火索
- 数学之美!~(02)十位伟大的数学家!