线程学习基础(1):单线程爬虫和多线程爬虫的效率比照

news2025/1/19 3:13:57

线程学习基础:单线程爬虫和多线程爬虫的效率比照

    • 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 requests

urls = [
    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 requests

urls = [
    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_thread
    start = time.time()
    single_thread()
    end = time.time()
    print("single thread cost:", end - start, "seconds")
    singleTime = end - start

    # multi_thread
    start = time.time()
    multi_thread()
    end = time.time()
    print("multi thread cost:", end - start, "seconds")
    multiTime = end - start

    print(str(singleTime / multiTime) + 'times')
  • 上面代码,是爬取了50页的网页页面。
  • 开始,还是先定义爬取的函数draw,然后定义一个单线程的函数,再定义一个多线程的函数。
  • 为了方便截图,我在draw函数里面的打印参数里面加了去掉换行符的代码。
  • 运行结果如图。
    在这里插入图片描述

5.3 速度对比:单线程爬虫VS多线程爬虫

  • 上面主程序中,为了对比单线程爬虫VS多线程爬虫的速度,定义了开始时间和结束时间的变量。
  • 然后分别对单线程爬虫和多线程爬虫运行时间进行对比,发现效率大大提高。速度差了十几倍。
  • 那么,爬取成千成万甚至几十G的数据,就更显得多线程的威力了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/161701.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三维空间中散点平面拟合方法

1、三点求平面方程、平面法向量和点到平面的距离 已知三点p1(x1,y1,z1),p2(x2,y2,z2),p3(x3,y3,z3), 要求确定的平面方程,关键在于求出平面的一个法向量 为此做向量p1p2(x2-x1,y2-y1,z2-z1), p1p3(x3-x1,…

Linux-8 用户管理

Linux-8 用户管理 什么是用户? Linux/Windows通过用户来管理和维护系统; Windows下的管理员用户:AdministratorLinux下的管理员用户:root Windows/Linux都是多用户系统 Windows同一时间只能使用1个用户Linux可以多用户同时登陆&…

STL - Vector容器

基本概念 功能: vector数据结构和数组十分类似,也成为单端数组 vector和普通数组的区别: 不同之处在于数组是静态空间,而vector可以动态扩展 动态扩展: 并不是在原空间后续再接空间&#x…

【pandas】用户手册:10分钟熟悉pandas(下)

数据分组 Splitting : 利用某些条件将数据进行分组Applying : 函数应用于每个单独的分组Combining : 合并最终的结果 df pd.DataFrame({"A": ["foo", "bar", "foo", "bar", "foo", "bar", "foo&q…

【正点原子FPGA连载】第十四章Linux基础外设的使用 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id692450874670 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html 第十四章Linux基…

百趣代谢组学文献分享:间歇性禁食调节糖尿病脑损伤多组学研究

百趣代谢组学文献分享,糖尿病已经成为一个全球问题,国际糖尿病联盟(IDF)发布的全球糖尿病地图(第9版)[1]显示,全球糖尿病患者人数不断上升,全球平均增长率为51%,目前有4.…

C#,图像二值化(23)——局部阈值的绍沃拉算法(Sauvola Thresholding)及源程序

1、局部阈值的绍沃拉算法(Sauvola Thresholding)Niblack和Sauvola阈值算法Niblack和Sauvola阈值是局部阈值技术,对于背景不均匀的图像非常有用,尤其是对于文本识别1、2。代替为整个图像计算单个全局阈值,通过使用考虑到…

【5】K8S_Deployment

目录 1、Deployment作用 2、deployment的冗余能力 3、deployment的多副本部署 4、deployment的扩缩容 5、deployment的自愈能力 6、滚动更新 7、版本回退 1、Deployment作用 控制Pod,使Pod拥有多副本,自愈,扩缩容等能力 2、deployme…

【正点原子FPGA连载】第十五章开发环境搭建 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id692450874670 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html 第十五章开发环境…

uniapp 窗口小工具、桌面小部件、微件(日历、时间) Ba-AwCalendarS

简介(下载地址) Ba-AwCalendarS 是一款窗口小工具(桌面小部件、微件)插件,默认为简单的时间样式,有其他界面需要,可联系作者定制。 支持定时更新(本插件为每分钟)支持点…

基于springboot,vue二手交易平台

开发工具:IDEA服务器:Tomcat9.0, jdk1.8项目构建:maven数据库:mysql5.7系统用户前台和管理后台两部分,项目采用前后端分离前端技术:vue elementUI服务端技术:springbootmybatis项目功…

【数据结构】开端序幕

写在前面,感同身受初学数据结构,是不是一脸懵,下面你中招了几条?😭怎么全是指针!指针都不会啊!怎么变量名那么长,好难理解啊!什么p,什么next,pp->next究竟…

LeetCode[1753]移除石头的最大得分

难度:中等题目:你正在玩一个单人游戏,面前放置着大小分别为 a、b和 c的 三堆 石子。每回合你都要从两个 不同的非空堆 中取出一颗石子,并在得分上加 1分。当存在 两个或更多 的空堆时,游戏停止。给你三个整数 a、b和 c…

动手深度学习-多层感知机

目录感知机多层感知机激活函数sigmoid函数tanh函数ReLU函数多层感知机的简洁实现参考教程:https://courses.d2l.ai/zh-v2/ 感知机 模型: 感知机模型就是一个简单的人工神经网络。 感知机是二分类的线性模型,其输入是实例的特征向量&#x…

智慧管廊智能化运维管理平台详情

运维管理平台 ​ 平台主界面完成各分系统情况的全局性展现,用图形界面的方法提升视觉效果感染力,根据图色区分正常、异常情况。 1、自然环境及设备监控 ​ 选用全景分层三维可视化地理信息系统及其多元化的二维在线地图从温度、风速、电力、排水、安防…

windows检测远程主机是否连通或者某个端口是否开启

文章目录一、检测主机是否连通步骤二、测试端口是否打开步骤telnet安装一、检测主机是否连通 ping命令是个使用频率极高的网络诊断工具,在Windows、Unix和Linux系统下均适用。它是TCP/IP协议的一部分,用于确定本地主机是否能与另一台主机交换数据报。根…

2022年度总结 EXI-小洲

文章目录一、第一次自我介绍二、2022我都干了些什么(我的收获)1.大专顺利毕业2.后端开发辞职3.第二次代表学校参加江西省职业院校大数据技能大赛4.专升本考试5.参加泰迪杯第五届"数据分析技能赛"6.在csdn开始写博文7.在本科阶段,我又认识了几个会喝点酒的…

【2022年度总结】总结过去,展望未来

文章目录前言回顾过去一、刷题道路两眼黑二、助人为乐本身便是一种快乐展望未来兔年Flag博客文章竞赛目标学习目标志同道合前言 注册CSDN一年了,新年伊始,正好趁着这个时间复盘一下逝去的2022! 很幸运,在对计算机知识懵懂无知的时…

分布式调度XXL-JOB急速入门

文章目录1.业界分布式定时任务框架简介2.分布式调度XXL-JOB核心特性3.Docker部署MySQL8.04.XXL-JOB数据库脚本介绍5.Docker部署XXL-JOB服务端6.XXL-JOB UI菜单模块介绍7.SpringBoot整合XXL-JOB8.分布式调度参数传递9.分布式调度日志埋点10.自定义返回执行成功或失败11.XXL-Job高…

C#上位机基础学习_基于SOCKET实现与PLC服务器的TCP通信(二)

C#上位机基础学习_基于SOCKET实现与PLC服务器的TCP通信(二) 测试软件: TIA PORTAL V15.1 S7-PLCSIM ADVANCED V3.0 Visual Studio 2019 在上次的分享中,我们了解了TIA博途一侧的具体组态配置,具体内容可参考以下链接中的内容: C#上位机基础学习_基于SOCKET实现与PLC服务…