Python爬虫:线程,进程与协程

以往的爬虫我们都采用单线程和同步的方式,这导致我们的爬虫及其脆弱,因为一点报错都会让它停下来,而且面对比较大的数据,爬虫只能选择等待,这种阻塞会消耗很多时间,为什么我们不把等待的这些时间去干别的事呢?

线程与进程

线程和进程是相似的 

一,概念梳理

线程: 程序内,可以直接被CPU调用的执行过程,是操作系统能够进行运算的最小单位,它被包含在进程中实际运作的单位。

进程:运行中的程序,每次我们执行应该程序,操作系统会自动地为这个程序准备一些必要的资源(分配内存,创造一个能执行的线程)

形象来说,线程就像是员工,进程就是公司,线程组成进程。如果我们想要提升效率,我们可以多招些员工(多线程)或者开一些分公司,连锁(多进程) 

二,代码实现

多线程

from threading import Thread
# def func(name):
#     for i in range(10):
#         print(name,i)#创建任务
def func_1(name):for i in range(100):print(name,i)if __name__ == '__main__':# func("A")# func("B")# func("C")# #创建线程t1 = Thread(target=func_1,args=("A",))t2 = Thread(target=func_1,args=("B",))t3 = Thread(target=func_1,args=("C",))t1.start()t2.start()t3.start()

实例化线程对象:Thread(taeget=目标函数,不要括号,args=()填参数,元组形式) 

开启线程:线程对象的start方法

面向对象写法 

from threading import Thread
class MyThread(Thread):def __init__(self,name):super(MyThread, self).__init__()self.name = namedef run(self):for i in range(100):print(self.name,i)if __name__ == '__main__':t1 = MyThread("A")t2 = MyThread("B")t3 = MyThread("C")t1.start()t2.start()t3.start()

需要注意的是,函数执行的任务必须重写到run方法中,其他的一样。

很快,一个一个实例化线程对象的方法无法满足我们了,如果我们要申请20个线程呢?这太繁琐了

 线程池的产生就是顺其自然的了

线程池

from concurrent.futures import ThreadPoolExecutordef func(name):for i in range(50):print(name,i)if __name__ == '__main__':with ThreadPoolExecutor(10) as t:t.submit(func,"A")t.submit(func,"B")t.submit(func,"C")

这大大地减轻了我们的工作量,我们只需要把任务丢进线程池里,它就会自动分配线程为我们处理,当然,最大线程数我们可以设置,上例使用了10个。 

好了,上面的所有情况我们都忽视掉了函数有返回值的情况是,那么,这种情况该怎么处理呢?

from concurrent.futures import ThreadPoolExecutordef func(name):print(name)return namedef fun(res):print(res.result())if __name__ == '__main__':with ThreadPoolExecutor(3) as t:t.submit(func,"A").add_done_callback(fun)t.submit(func,"B").add_done_callback(fun)t.submit(func,"C").add_done_callback(fun)

或者

from concurrent.futures import ThreadPoolExecutordef func(name):print(name)return namedef fun(res):print(res.result())if __name__ == '__main__':with ThreadPoolExecutor(3) as t:results = t.map(func,["A","B","C"])for result in results:print(result)

 这样我们就可以获取函数返回值了。

多进程

from multiprocessing import Process
from concurrent.futures import ProcessPoolExecutor
def func(name):for i in range(100):print(name,i)if __name__ == '__main__':p1 = Process(target=func,args=("A",))p2 = Process(target=func,args=("B",))p3 = Process(target=func,args=("C",))p1.start()p2.start()p3.start()

 怎么样,对比一下多线程,你会发现代码上除了调的类不一样以外,就没区别了,多进程的进程池和线程池几乎一模一样,这里就不赘述了,可以自己尝试一下,进程池上面代码有名字~

线程和进程是相似的 

那么,多进程和多线程的应用场景有什么不同呢?

多线程:任务相对统一,互相特别相似

多进程:多个任务相互独立,很少有交集

多任务异步协程

协程:协程是一种比函数更加强大的控制流结构,它可以挂起(暂停)自身的执行并在稍后从上次挂起的地方恢复执行。协程允许在单个线程内进行非阻塞的协作式多任务处理,这意味着程序可以在等待某个耗时操作(如I/O操作、网络请求)完成的同时,去做其他事情,从而提高整体效率。协程拥有自己的执行上下文(包括局部变量和指令指针),可以在多个协程之间方便地切换。

简单理解,多线程可以理解为我们不停的切换cpu运算对象,任务不动,CPU动。而协程是单线程中,通过移动任务来实现的,比如任务1进入这条线程中,进行计算.....直到产生IO阻塞,任务1就出线程,任务2进入线程,以此类推,当任务1IO阻塞结束,再让它回到线程(如果还有必要的话)。这个过程实质上是CPU不动,任务移动。这其实效率更高,因为CPU调用切换是需要消耗内存的,它是属于系统层面的问题,而协程只需要切换任务,这是代码层面的问题,实际上是不需要多少时间和空间的。

异步协程代码实现

import asyncioasync def func():print("我是函数")if __name__ == '__main__':#协程对象想要执行,必须借助于 event_loopf = func()event_loop = asyncio.get_event_loop()event_loop.run_until_complete(f)#eventloop运行协程对象,直到该对象内的内容执行完毕为止

 这是协程的基本结构,async表示异步,因为我们需要IO阻塞,想象一下如果我们申请网页响应中不执行IO阻塞,那在申请的同时代码就已经跑到下面去了,如果我们下面需要这个网页的源码呢?这就必然报错了,所以这就是为什么我们的函数使用了异步操作,本质还是在IO阻塞上。


import asyncioasync def func1():print("我是func1")await asyncio.sleep(1)print("func1结束")async def func2():print("我是func2")await asyncio.sleep(2)print("func2结束")async def func3():print("我是func3")await asyncio.sleep(3)print("func3结束")if __name__ == '__main__':f1 = func1()f2 = func2()f3 = func3()tasks = [f1,f2,f3]asyncio.run(asyncio.wait(tasks))

上例我们创建了三个任务,并将这三个任务添加到了协程中,wait()为何意?这是为了让我们三个任务必须执行完才关闭eventloop,要不然还有任务在io阻塞,协程直接关了怎么办。

异步协程的函数返回值

import asyncio
async def func1():print("我是func1")await asyncio.sleep(1)print("func1结束")return "func1的返回值"async def func2():print("我是func2")await asyncio.sleep(2)print("func2结束")return "func2的返回值"async def func3():print("我是func3")await asyncio.sleep(3)print("func3结束")return "func3的返回值"async def main():f1 = func1()f2 = func2()f3 = func3()tasks = [asyncio.create_task(f1),asyncio.create_task(f2),asyncio.create_task(f3)]# done,padding = await asyncio.wait(tasks)# for res in done:#     print(res.result())# gather和wait区别:gather返回值是有顺序的(按照你添加任务的顺序)result = await asyncio.gather(*tasks,return_exceptions=False)#return exception=true表示如果任务中有错误信息,则返回错误信息,其他任务正常执行。print(result)
if __name__ == '__main__':asyncio.run(main())

 解释请看代码注释~

创作不易,点个小赞鼓励一下呗~ 

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

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

相关文章

研究论文的蓝图:精通论文大纲的编写技巧

研究论文大纲是一个补充文件,描述了按计划顺序纳入论文的所有主题,通常按段落分割。正常的研究论文大纲包括额外的细节,例如子主题和证据来源,以帮助作者保持结构。本文讨论了研究论文大纲的内容以及如何撰写。 研究论文大纲的含…

C#语言入门

一、基础知识 1. 程序语言是什么 用于人和计算机进行交流,通过程序语言让计算机能够响应我们发出的指令 2. 开发环境 IDE,集成开发环境。它就是一类用于程序开发的软件,这一类软件一般包括了代码编辑、编译器、调试器、图形用户界面等等工…

STM32独立看门狗,实现单片机自动重启

今天学习了一下独立看门狗,看门狗的主要作用就是防止程序中有死循环或是不知道的bug,而造成在while循环中没有及时喂狗,程序就会控制单片机重启复位,从而不至于影响程序一直不能正常工作。 其实看门狗的应用也不是很复杂&#xf…

1020. 【USACO题库】2.1.1 The Castle城堡

题目描述 以一个几乎超乎想像的运气,农民约翰在他的生日收到了一张爱尔兰博彩的奖券。 这一张奖券成为了唯一中奖的奖券。 农民约翰嬴得爱尔兰的乡下地方的一个传说中的城堡。 吹牛在他们威斯康辛州不算什么,农民约翰想告诉他的牛所有有关城堡的事。 他想知道城堡有多少房间…

光伏光热一体化技术PVT

1、PVT集热器简介 太阳能光伏光热一体化组件主要由光伏与光热两个部分组成。光伏部分采用技术成熟的太阳能光伏面板,通过控制系统为建筑提供所需电能,主要包括光伏电池、蓄电池、逆变器和控制器等构件。光热部分主要为集热器,将太阳能转换为热…

力扣例题(接雨水)

链接: . - 力扣(LeetCode) 题目描述: 思路: 判断一块地方是否可以接到雨水,只需要判断他是否有左右边界使他可以接到水 左右边界分别为此处左侧的最高点和右侧的最高点 同时此处可接雨水的高度为左右两…

基于Pytorch深度学习——GPU安装/使用

本文章来源于对李沐动手深度学习代码以及原理的理解,并且由于李沐老师的代码能力很强,以及视频中讲解代码的部分较少,所以这里将代码进行尽量逐行详细解释 并且由于pytorch的语法有些小伙伴可能并不熟悉,所以我们会采用逐行解释小…

《QT实用小工具·四十九》QT开发的轮播图

1、概述 源码放在文章末尾 该项目实现了界面轮播图的效果,包含如下特点: 左右轮播 鼠标悬浮切换,无需点击 自动定时轮播 自动裁剪和缩放不同尺寸图片 任意添加、插入、删除 单击事件,支持索引和自定义文本 界面美观,圆…

开源免费的网盘项目Cloudreve,基于Go云存储个人网盘系统源码(七牛、阿里云 OSS、腾讯云 COS、又拍云、OneDrive)

项目简介: 在现今的网盘服务中,用户经常遭遇限速和价格上涨的问题,这无疑增加了使用上的困扰。 为此,我今天要介绍一款开源且免费的网盘项目——Cloudreve。 这个项目是基于Go语言开发的云存储个人网盘系统,支持多种…

[笔试训练](十二)

目录 034:删除公共字符串 035:两个链表的第一个公共节点 036:mari和shiny 034:删除公共字符串 删除公共字符_牛客题霸_牛客网 (nowcoder.com) 题解: 用哈希记录好第二个字符串中的字符,再遍历一遍第一个字符串,只将没有记录的字符加在结果字符串上。…

[C++][数据结构]哈希1:哈希函数的介绍与线性探测的实现

前言 学完了二叉树,我们要学当前阶段数据结构的最后一个内容了:哈希!! 引入 先来介绍两个用哈希封装的两个容器:unordered_map unordered_set 与map和set的不同: map/set是双向迭代器,而另…

【已解决】VSCode 连接远程 Ubuntu :检测到 #include 错误。请更新 includePath。

文章目录 1. 环境声明2. 解决过程 1. 环境声明 即使是同一个报错,在不同的环境中,报错原因、解决方法都是不同的,本文只能解决跟我类似的问题,如果你发现你跟我遇到的问题不太一样,建议寻找其他解法。 必须要吐槽的是…

STD10A230XCB电源模块STD05A230XCB整流模块介绍

STD10A230XCB电源模块STD05A230XCB整流模块介绍,直流屏电源模块STD05A230XCB,整流模块STD10A115XCB,STD20A115XCB,STD10A230X,STD05A230X,直流屏充电模块的关键词: 电力智能高频开关充电模块STD20A230XCB,高…

【科研技术】华为为什么不给微信特权?

::: block-1 “时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验,帮助大家尽早适应研究生生活,尽快了解科研的本质。祝一切顺利!—…

# 从浅入深 学习 SpringCloud 微服务架构(七)Hystrix(4)

从浅入深 学习 SpringCloud 微服务架构(七)Hystrix(4) 一、hystrix:使用 turbine 聚合所有的 hytrix 的监控数据测试。创建父工程 spring_cloud_hystrix_demo,导入相关依赖坐标。并在父工程 spring_cloud_…

C语言/数据结构——每日一题(移除链表元素)

一.前言 今天在leetcode刷到了一道关于单链表的题。想着和大家分享一下。废话不多说,让我们开始今天的知识分享吧。 二.正文 1.1题目要求 1.2思路剖析 我们可以创建一个新的单链表,然后通过对原单链表的遍历,将数据不等于val的节点移到新…

图床搭建GitHub+PicGo+jsdelivr(CDN)+Typora(内附加速工具)

目录 安装PicGo GitHub配置与加速器 配置PicGo 使用typroa 安装PicGo PicGo是一个用于上传图片的客户端,支持拖拽上传、剪贴板上传,功能十分方便。 下载地址: https://github.com/Molunerfinn/PicGo/releases 个人网盘自取版本2.4.0…

了解并学会使用反射

目录 一、反射的应用场景(简单了解) 二、反射的定义 三、关于反射的四个重要的类 四、反射的使用 1.Class获取一个class对象的方式 方式一:forName(): 方式二:封装类.Class: …

【stomp 实战】Spring websocket 用户订阅和会话的管理源码分析

通过Spring websocket 用户校验和业务会话绑定我们学会了如何将业务会话绑定到spring websocket会话上。通过这一节,我们来分析一下会话和订阅的实现 用户会话的数据结构 SessionInfo 用户会话 用户会话定义如下: private static final class Sessio…

怎么让电脑耳机和音响都有声音

电脑耳机音响不能同时用没声音怎么办 一般来说,重新开机后问题能够得到解决。右击“我的电脑”---“属性”---“硬件”---“设备管理器”,打开“声音、视频和游戏控制器”有无问题,即看前面有没有出现黄色的“”。 如果您的 电脑 耳机能正常…