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.mzph.cn/news/593646.shtml

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

相关文章

网络安全—认证技术

文章目录 加密认证对称密钥体制公钥密码体制公钥的加密公钥身份认证和加密 鉴别码认证MAC鉴别码 报文摘要认证认证 加密只认证数字签名 通过了解以前前辈们使用的消息认证慢慢渐进到现代的完整的认证体系。所以在学习的时候也很蒙圈&#xff0c;因为前期的很多技术都是有很严重…

这次,数据泄露的目标受害者指向了---救护车服务公司

已停业的救护车服务遭到勒索软件攻击导致近百万人受到威胁&#xff01; 此次数据泄露的目标受害者是法伦救护车服务公司&#xff0c;该公司是Transformative Healthcare的子公司。ALPHV勒索软件团伙声称对2023年4月下旬对Transformative Healthcare的攻击负责&#xff0c;并导…

SpringBoot 集成支付宝支付

网页操作步骤 1.进入支付宝开发平台—沙箱环境 使用开发者账号登录开放平台控制平台 2.点击沙箱进入沙箱环境 说明&#xff1a;沙箱环境支持的产品&#xff0c;可以在沙箱控制台 沙箱应用 > 产品列表 中查看。 3.进入沙箱&#xff0c;配置接口加签方式 在沙箱进行调试前…

rime中州韵小狼毫 inputShow lua Translator 输入字符透传翻译器

在 rime中州韵小狼毫 help lua Translator 中我们分享了如何使用 lua 脚本定义一个 translator&#xff0c;并以 五笔・拼音 为例引用了该 translator&#xff0c;并且达到了预期的效果。 今天&#xff0c;我们继续通过 lua 脚本为 rime中州韵/小狼毫 输入法打造一个 translat…

实验3 vTPM相关

可以代做实验手册等私聊 一、实验目的 1.了解vTPM原理和相关知识&#xff1b;2.创建具备vTPM的虚拟机&#xff1b;3.加深对可信计算技术的理解。 二、实验内容 安装seabios&#xff0c;libtpms&#xff0c;swtpm&#xff0c;qemu‐tpm&#xff1b;启动vTPM&#xff1b;安装…

守正出奇,穿越周期 - Bytebase 的 2023

前情提要&#xff1a;Bytebase 的 2022&#xff5c;埋头苦干&#xff0c;孕育希望 产品迭代 2023 年共发布了 25 个版本。这个数字和 2022 年一样&#xff0c;除开春节和一次全员疫情&#xff0c;做到了两周一次的更新。 版本号从 1.11.0 升级到了 2.13.0。其中在 5 月份&…

MySQL常见面试题总结

1.MySQL基础 1.1什么是关系型数据库&#xff1f; 顾名思义&#xff0c;关系型数据库&#xff08;RDB&#xff0c;Relational Database&#xff09;就是一种建立在关系模型的基础上的数据库。关系模型表明了数据库中所存储的数据之间的联系&#xff08;一对一、一对多、多对多…

图像分割-漫水填充法 floodFill

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 本文的C#版本请访问&#xff1a;图像分割-漫水填充法 floodFill (C#&#xff09;-CSDN博客 FloodFill方法是一种图像处理算法&#…

C++上位软件通过Snap7开源库访问西门子S7-200/合信M226ES数据块的方法

前言 上一篇文章中介绍了Snap7访问西门子S7-1200/S7-1500 DB块的方法&#xff0c;对于S7-200PLC是没有数据块访问的。S7-200PLC中Snap7只能通过访问MB块&#xff0c;VB块的方法进行和PLC之间的Snap7通信和数据交换。手头没有S7-200PLC故通过合信CTMC M226ES运动控制器进行测试&…

SSM的校园二手交易平台----计算机毕业设计

项目介绍 本次设计的是一个校园二手交易平台&#xff08;C2C&#xff09;&#xff0c;C2C指个人与个人之间的电子商务&#xff0c;买家可以查看所有卖家发布的商品&#xff0c;并且根据分类进行商品过滤&#xff0c;也可以根据站内搜索引擎进行商品的查询&#xff0c;并且与卖…

如何用js动态修改字体大小

在项目中&#xff0c;我们常常会遇到使用v-html渲染文本的情况。 如果需要点击大中小三个字号按钮&#xff0c;需要修改字体的大小。那我们应该怎么做呢 function fontSize(element, type) {let size {big: 22,middle: 16,small: 12};var result element.innerHTML.replac…

hAdmin漂亮的后台html模板免费下载

hAdmin漂亮的后台html模板免费下载-遇见你与你分享

autograd与逻辑回归

一、autograd—自动求导系统 torch.autograd.backward() torch.autograd.backward()是PyTorch中用于计算梯度的函数。以下是对该函数的参数的解释&#xff1a; 功能&#xff1a;自动求取梯度 • tensors: 用于求导的张量&#xff0c;如 loss • retain_graph : 保存计算图 •…

【Linux】基本指令了解(一)

&#x1f497;个人主页&#x1f497; ⭐个人专栏——数据结构学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读&#xff1a;1. 认识Linux1.1 什么是Linux1.2 Linux特点 2. ls指令3. pwd命令4. cd 指令5. touch命令6. mkdir指令7. …

SSM共享汽车租赁平台----计算机毕业设计

项目介绍 本项目分为前后台&#xff0c;前台为普通用户登录&#xff0c;后台为管理员登录&#xff1b; 管理员角色包含以下功能&#xff1a; 管理员登录,修改管理员信息,用户信息管理,管理新闻公告,汽车品牌信息管理,城市信息管理,租赁点信息管理,共享汽车信息管理,汽车订单信…

【Linux Shell】1. Shell 简述

文章目录 【 1. Shell 解释器、Shell语言、Shell脚本 】【 2. Shell 环境 】【 3. 一个简单的 Shell 脚本 】3.1 Shell 脚本的编写3.2 Shell 脚本的运行3.2.1 作为可执行程序运行 Shell 脚本3.2.2 作为解释器参数运行 Shell 脚本 【 1. Shell 解释器、Shell语言、Shell脚本 】 …

解决Redis序列化乱码问题

如果我们使用原生的JDK序列化&#xff0c;那么当我们将数据存储到Redis中就会出现乱码的情况 为了解决这个问题我们需要重写RedisTemplate从而解决序列化乱码问题 首先在Maven中引入相应的依赖 <dependency> <groupId>com.fasterxml.jackson.core</group…

七、Redis 缓存 —— 超详细操作演示!

七、Redis 缓存 —— 超详细操作演示&#xff01; 七、Redis 缓存7.1 Jedis 客户端7.1.1 Jedis 简介7.1.2 创建工程7.1.3 使用 Jedis 实例7.1.4 使用 JedisPool7.1.5 使用 JedisPooled7.1.6 连接 Sentinel 高可用集群7.1.7 连接分布式系统7.1.8 操作事务 7.2 金融产品交易平台7…

Python怎么修改进程名称

目录 一、进程名称的概念 二、Python修改进程名称的方法 三、代码示例与使用说明 四、注意事项 五、适用场景 六、总结 Python是一种强大的编程语言&#xff0c;广泛应用于各种应用程序的开发。在Python中&#xff0c;修改进程名称可以通过多种方式实现。下面我们将深入探…

python c语言 代码动态检查,python c语言语法分析

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python c语言 代码动态检查&#xff0c;python c语言语法分析&#xff0c;今天让我们一起来看看吧&#xff01; Source code download: 本文相关源码 初学编程&#xff0c;应该学习哪一门编程语言&#xff0c;有不少人感…