Python爬虫中的协程

协程

基本概念

协程:当程序执行的某一个任务遇到了IO操作时(处于阻塞状态),不让CPU切换走(就是不让CPU去执行其他程序),而是选择性的切换到其他任务上,让CPU执行新的任务,当原来的任务不处于阻塞状态后,CPU可以快速的回到之前的任务继续执行,这样就不用让原本的程序去排队等待CPU调度。

微观上看,任务是一个一个的切换执行,切换条件就是某一个任务有IO操作, 而宏观上,我们看到的是多个任务一起执行,这就是多任务异步操作。上面的一切的前提就是单线程的情况下,因为多线程可以多个线程同时干多件事。

import timedef func():print('first, hi!')# 让程序睡眠3秒钟,此时线程处于阻塞状态,CPU不为线程工作# 当我们爬取一个网页时,向一个url发送请求,会通过网络传输将请求发送到服务器# 然后服务器会处理请求、准备数据、将数据通过网络传输回客户端等工作# 这一系列的操作也会耗费时间,所以在从发送请求开始,到接收服务器返回的数据这一段时间内# 即在网络请求返回数据之前,程序也处于阻塞状态# 程序进行处于IO操作时是处于阻塞状态的time.sleep(3)print('second, hello..')if __name__ == '__main__':func()

协程和线程的区别(个人理解)

昨天仔细想的时候,感觉协程和线程很像,不知道它们之间的区别在哪,然后百度了一下,在这里说一下自己的理解(很不官方,不懂的可以百度一下,别人写的会比较详细和专业)。

打个比喻,一个公司有很多员工,老板给每个员工分配任务,员工之间各有分工,每个人负责自己的工作,如果遇到一个很会压榨人的老板,就会给每个员工安排很多任务。员工在完成自己分配到的多个任务时,因为自己只有一个人,不能同时把多个任务一起干,所以肯定是某个时刻内只干一件事。但是为了提高工作效率,在某个任务需要等待时,员工肯定不能傻傻的等着,而是利用这个等待的时间去干另一个任务(毕竟手上被万恶的资本家分配了很多活),比如正在跑的一个程序A要运行很久,那么在这个程序A运行的时间里,员工肯定去写另一个程序B了,如果这个程序B写完后也要运行很久,那么员工就会去完成程序C,或者此时程序A运行完了,接着完成程序A.....

上面所说的一个公司有多个员工,那么每个员工相当于一个线程,多个员工各有分工干自己的活,就是多个线程之间独立完成自己的工作。而一个员工充分利用时间完成多个任务(从一段时间上看(宏观),如一周内,员工同时完成多个任务,但是实际上(微观),某个时刻员工只做一件事),这每一个任务就是协程,所以协程实际上是一个单线程,宏观上同步完成多个任务,微观上异步完成多个任务。

协程可以充分的让一个线程忙起来,提高效率,不然当某个任务阻塞时,线程就处于空闲的等待状态,这使得线程资源没有得到充分利用,执行效率也大打折扣,就像老板想让打工人一刻都不停的给他创造价值一样。

用Python编写协程的程序

单个异步任务

有四种方式,但这里只选择其中的一种,如以下代码所示:

import asyncio# 这种写法就是普通的函数
# def func():
#     print('你好,我是张三!')
#
#
# if __name__ == '__main__':
#     func()# 在函数前面加async关键字,就表明该函数是异步协程函数
async def func():print('你好,我是张三!')if __name__ == '__main__':# func()  # 如果直接调用,会得到一个警告:RuntimeWarning: ...g = func()  # 此时函数是一个异步协程函数,执行函数得到一个协程对象"""输出:<coroutine object func at 0x000001F823066960>sys:1: RuntimeWarning: coroutine 'func' was never awaited"""print(g)asyncio.run(g)  # 协程程序的运行需要asyncio模块的支持

多个异步任务

import asyncio
import time# 在函数前面加async关键字,就表明该函数是异步协程函数
async def func1():print('你好,我是张三!')time.sleep(3)print('你好,我是张三!')async def func2():print('你好,我是李四!')time.sleep(2)print('你好,我是李四!')async def func3():print('你好,我是王五!')time.sleep(4)print('你好,我是王五!')if __name__ == '__main__':f1 = func1()f2 = func2()f3 = func3()# 把多个异步任务放到一个列表中tasks = [f1, f2, f3]t1 = time.time()# 一次性启动多个异步任务(协程)asyncio.run(asyncio.wait(tasks))t2 = time.time()print(t2 - t1)

上面三个函数是异步协程操作,理论上执行时间应该会小于9秒,因为异步任务会在某一个任务阻塞时去调用其他任务,但是观察上述代码执行时间,发现和同步执行三个函数效果一样,都是用了9秒多,如下图。出现这种的情况的原因是:函数里的time.sleep()是同步操作,而异步协程函数中出现同步操作的时候,异步就中断了,也就是说,当异步函数中有同步操作时,CPU不会切换去调用其他任务,而是像同步函数那样,执行完一个任务再去执行另一个任务(在这个例子中,就是执行完func1,再执行func2,再执行func3)。

修改上述代码,实现异步操作效果,如下:

import asyncio
import time# 在函数前面加async关键字,就表明该函数是异步协程函数
async def func1():print('你好,我是张三!')# time.sleep(3)  # 异步程序中出现同步操作,会中断异步,即不会切换任务执行# 异步操作代码,表示挂起任务,让任务睡眠3秒,然后切换CPU去执行其他任务await asyncio.sleep(3)print('你好,我是张三!')async def func2():print('你好,我是李四!')# time.sleep(2)await asyncio.sleep(2)print('你好,我是李四!')async def func3():print('你好,我是王五!')# time.sleep(4)await asyncio.sleep(4)print('你好,我是王五!')# 一般不会直接像下面那样调用多个异步任务,而是把它包装在一个异步协程函数里
# if __name__ == '__main__':
#     f1 = func1()
#     f2 = func2()
#     f3 = func3()
#     # 把多个异步任务放到一个列表中
#     tasks = [f1, f2, f3]
#     t1 = time.time()
#     # 一次性启动多个异步任务(协程)
#     asyncio.run(asyncio.wait(tasks))
#     t2 = time.time()
#     print(t2 - t1)async def main():# 写法一(不推荐)# await 都是写在异步协程函数里,即与async配套使用# await后一般跟协程对象、task等对象# await表示挂起某个异步任务,即是执行某个异步任务# await asyncio.create_task(func1())# await asyncio.create_task(func2())# await asyncio.create_task(func3())# 写法二(推荐)tasks = [# asyncio.create_task(func1()) 把协程对象包装成task对象asyncio.create_task(func1()),asyncio.create_task(func2()),asyncio.create_task(func3())]# 这里await作用和上面一样,表示挂起协程对象,即会异步执行tasks列表中的异步任务await asyncio.wait(tasks)if __name__ == '__main__':t1 = time.time()asyncio.run(main())t2 = time.time()print(t2 - t1)

使用异步模拟爬虫程序

import asyncioasync def download(url):print('开始下载...')await asyncio.sleep(2)print('下载完成!')async def main():tasks = []urls = ['url1', 'url2', 'url3']for url in urls:d = download(url)  # 得到一个异步协程对象# asyncio.create_task(d) 把协程对象包装成task对象tasks.append(asyncio.create_task(d))await asyncio.wait(tasks)if __name__ == '__main__':asyncio.run(main())

异步发送http请求

以下代码是根据多个图片地址异步下载图片

import asyncio
# 下载命令:pip install aiohttp
import aiohttp# 图片地址
urls = ["https://img95.699pic.com/photo/50165/7667.jpg_wh860.jpg","https://bpic.588ku.com/back_origin_min_pic/20/04/19/f753e29e3dbe2ad75b8f6d6053199faa.jpg"
]async def download(url):file_name = url.rsplit('/', 1)[1]# aiohttp.ClientSession()对象等价于requests模块,所以也有get、post方法# 且用法差不多async with aiohttp.ClientSession() as req:  # => req = aiohttp.ClientSession()# 因为是异步操作,所以要加上async关键字# with的作用和文件操作中的with类似,可以管理上下文,在使用完req对象之后会自动关闭# req.get(url) 发送请求获取图片数据async with req.get(url) as resp:  # => resp = req.get(url)# 这里的文件读写操作也是IO操作,也是会造成阻塞,所以也可以通过异步协程来完成# 具体可以学习aiofiles模块来实现with open(file_name, mode='wb') as f:# resp.content.read()是异步操作,所以前面要加await表示挂起# 挂起的意思就是resp.content.read()什么时候有东西了什么时候写入文件# 即什么时候有需要的内容了什么时候进行对应的操作# resp.content.read() 表示以字节的形式读取返回的数据的内容# 在这里就是读取图片的字节数据,然后存入文件,即保存图片数据f.write(await resp.content.read())# req.close() 使用with之后不用手动写上这句话print(file_name, '下载完成')async def main():tasks = [asyncio.create_task(download(url)) for url in urls]await asyncio.wait(tasks)if __name__ == '__main__':asyncio.run(main())

使用异步爬虫爬取西游记小说内容

详见:异步爬取西游记

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

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

相关文章

引导过程的解析以及教程za

bios加电自检------mbr--------grub-------加载内核文件------启动第一个进程 bios的主要作用&#xff1a;检测硬件是否正常&#xff0c;然后根据bios中的启动项设置&#xff0c;去找内核文件 boot开机启动项顺序&#xff0c;你可以把内核文件放在何处&#xff1f; 1.硬盘 …

MySQL将多条数据合并成一条的完整示例

数据库中存的是多条数据&#xff0c;展示的时候需要合并成一条 数据表存储形式如下图 以type分组&#xff0c;type相同的算一条&#xff0c;且保留image和link的所有数据&#xff0c;用groupBy只保留一条数据 解决方案&#xff1a;用GROUP_CONCAT 完整语法如下 group_concat…

基于YOLOv8深度学习的人脸面部表情识别系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

10 个值得收藏的顶级手机数据恢复软件【2024年最新】

手机数据恢复&#xff0c;不要担心&#xff0c;今天就给大家分享10款数据恢复软件&#xff01; 现代人的手机中存储了许多重要数据&#xff0c;如照片、视频、消息、联系人等文件&#xff0c;如果手机损坏或数据丢失&#xff0c;这是一件非常烦恼的事情。此时&#xff0c;一款好…

解决jenkins的Exec command命令不生效,或者执行停不下来的问题

Jenkins构建完后将war包通过 Publish Over SSH 的插件发布到服务器上&#xff0c;在服务器上执行脚本时&#xff0c;脚本中的 nohup 命令无法执行&#xff0c;并不生效&#xff0c;我配置的Exec command命令是后台启动一个war包&#xff0c;并输出日志文件。 nohup java -jar /…

nginx源码分析-4

这一章内容讲述nginx的模块化。 ngx_module_t&#xff1a;一个结构体&#xff0c;用于描述nginx中的各个模块&#xff0c;其中包括核心模块、HTTP模块、事件模块等。这个结构体包含了一些模块的关键信息和回调函数&#xff0c;以便nginx在运行时能够正确地加载和管理这些模块。…

《动手学深度学习》学习笔记 第5章 深度学习计算

本系列为《动手学深度学习》学习笔记 书籍链接&#xff1a;动手学深度学习 笔记是从第四章开始&#xff0c;前面三章为基础知道&#xff0c;有需要的可以自己去看看 关于本系列笔记&#xff1a; 书里为了让读者更好的理解&#xff0c;有大篇幅的描述性的文字&#xff0c;内容很…

算法学习系列(十四):并查集

目录 引言一、并查集概念二、并查集模板三、例题1.合并集合2.连通块中点的数量 引言 这个并查集以代码短小并且精悍的特点&#xff0c;在算法竞赛和面试中特别容易出&#xff0c;对于面试而言&#xff0c;肯定不会让你去写一两百行的代码&#xff0c;一般出的都是那种比较短的…

[GKCTF 2020]ez三剑客-eztypecho

[GKCTF 2020]ez三剑客-eztypecho 考点&#xff1a;Typecho反序列化漏洞 打开题目&#xff0c;发现是typecho的CMS 尝试跟着创建数据库发现不行&#xff0c;那么就搜搜此版本的相关信息发现存在反序列化漏洞 参考文章 跟着该文章分析来&#xff0c;首先找到install.php&#xf…

Unable to connect to Redis server

报错内容&#xff1a; Exception in thread "main" org.redisson.client.RedisConnectionException: java.util.concurrent.ExecutionException: org.redisson.client.RedisConnectionException: Unable to connect to Redis server: 175.24.186.230/175.24.186.230…

使用idea构建父子类springboot项目教程

第一步创建一个父类java项目&#xff08;最外层java项目&#xff09; 1.点击File 然后点击new 再点击Project 2.点击Maven 配置Java版本 再点击next 3.GroupId&#xff1a;包结构&#xff0c;ArtifactId&#xff1a;项目名称&#xff0c;填写完&#xff0c;点击next 4.点击…

IOS - 手机安装包 ipa 常见几种方式

安装 ipa 包的方法有很多中&#xff0c;可以通过不同的软件安装&#xff0c;本文只列出了常用的几种&#xff0c;做个简单的归纳整理 1、iTunes 安装 数据线连接手机之后&#xff0c;会自动连接iTunes&#xff0c;&#xff08;第一次连接的时候会提示是否信任此电脑&#xff0…

基于springboot的火锅店管理系统设计与实现

&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;一 、设计说明 1.1选题动因 当前…

打造绿色饲养链:河南恩珅德农业引领可持续农业发

在河南恩珅德农业的引领下&#xff0c;可持续农业的概念得到了更进一步的实践和推动。其致力于打造绿色饲养链的努力&#xff0c;旨在通过创新的理念和科技手段&#xff0c;实现饲养业的可持续发展。本文将深入探讨河南恩珅德农业是如何引领可持续农业发展&#xff0c;打造绿色…

Selenium教程06:单选框+多选框+下拉框组件的示例练习

1.Radio单选框的示例用法&#xff0c;通过网页元素class和type属性多条件共同定位元素&#xff0c;模拟依次选中Android&#xff0c;Apple&#xff0c;Windows。 网页元素结构 <input type"radio" class"ivu-radio-input" name"ivuRadioGroup_170…

Flink-【时间语义、窗口、水位线】

1. 时间语义 1.1 事件时间&#xff1a;数据产生的事件&#xff08;机器时间&#xff09;&#xff1b; 1.2 处理时间&#xff1a;数据处理的时间&#xff08;系统时间&#xff09;。 &#x1f330;&#xff1a;可乐 可乐的生产日期 事件时间&#xff08;可乐产生的时间&…

240101-5步MacOS自带软件无损快速导出iPhone照片

硬件准备&#xff1a; iphone手机Mac电脑数据线 操作步骤&#xff1a; Step 1: 找到并打开MacOS自带的图像捕捉 Step 2: 通过数据线将iphone与电脑连接Step 3&#xff1a;iphone与电脑提示“是否授权“&#xff1f; >>> “是“Step 4&#xff1a;左上角选择自己的设…

石头剪刀布游戏 - 华为OD统一考试

OD统一考试 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 石头剪刀布游戏有 3 种出拳形状: 石头、剪刀、布。分别用字母 A,B,C 表示游戏规则&#xff1a; 出拳形状之间的胜负规则如下: A>B; B>C; C>A&#xff1b; 左边一个字母&#xff0c;…

04.MySQL的基本操作

MySQL的基本操作 一、连接和断开MySQL服务器1、通过系统服务器启动、停止MySQL服务器2、通过命令提示符&#xff08;DOS&#xff09;启动、停止MySQL服务器2.1 启动 MySQL 服务器&#xff1a;2.2 停止 MySQL 服务器&#xff1a;2.3 登录和退出mysql 二、创建和管理数据库2.1 创…

东信免驱系列身份证阅读器串口通讯协议解析示例,适用于单片机、ARM等系统开发集成使用

完整的一次读卡流程包括&#xff1a; 身份证寻卡 > 身份证选卡 > 身份证读卡&#xff0c;三个步骤 缺一不可&#xff08;见通讯协议&#xff09;。 寻卡&#xff1a;EA EB EC ED 04 00 B0 B4 BB 返回&#xff1a;EA EB EC ED 05 00 00 B0 B5 BB 选卡&#xff1a;EA …