python项目实战——多协程下载美女图片
协程
文章目录
- 协程
- 协程的优劣势
- 什么是IO密集型任务
- 特点
- 示例
- 与 CPU 密集型任务的对比
- 处理 I/O 密集型任务的方式
- 总结
- 创建并使用协程
- asyncio模块
- 创建协程函数
- 运行协程函数asyncio.run(main())
- aiohttp模块
- 调用aiohttp模块步骤
- aiofiles————协程异步函数
- 遇到的问题
- 一 await asyncio.wait(task)的作用
- 1. **理解 `await` 的作用**
- 2. **`asyncio.wait(task)` 的作用**
- 3. **启动多个任务**
- 多协程案例——爬取图片
- 完整代码
- 设计思路
- 按顺序解读代码
- 主函数
🌟 亲爱的读者们, 🌟
感谢你们访问我的博客!如果你希望更深入、透彻地了解文章中的内容,欢迎随时私信我。我可以为你录制视频讲解,让知识变得更加生动有趣。
当然,若你们对这个想法感兴趣的朋友们越多,我会更有动力去制作这些视频哦!让我们一起探索更多的知识,共同成长!
期待你的私信!📩
协程(coroutine):也叫作微线程,纤程,协程是单线程下的并发。
协程的作用:在执行函数A时,随时中断去执行函数B,然后再中断函数B.返回来执行函数A,该操作类似多线程,但协程中只有一个线程在执行。
微观上:一个一个任务的切换,切换条件一般是IO操作
宏观上:是多个任务在同时执行——多任务异步操作
协程的优劣势
-
协程的优势:
非常适用于I/O密集型任务;
执行效率高(切换函数,而不切换线程,没有多余开销)
不需要锁机制。
-
协程的劣势:
无法利用多核资源
进行阻塞操作会阻塞掉整个程序。
什么是IO密集型任务
I/O 密集型任务(I/O-bound task)是指那些在执行过程中主要受限于输入/输出(I/O)操作性能的任务。这类任务的执行效率往往取决于数据的读写速度,而不是 CPU 处理能力。
特点
- 依赖于外部设备:I/O 密集型任务常常涉及与外部设备的交互,如硬盘、网络、数据库等。
- 等待时间长:由于 I/O 操作(如文件读取、网络请求)通常比 CPU 操作慢,I/O 密集型任务在执行时可能会有较长的等待时间。
- CPU 空闲:在等待 I/O 操作完成时,CPU 可能处于空闲状态,未能充分利用计算资源。
示例
- 文件读取/写入:长时间读取或写入大文件。
- 网络请求:等待远程服务器的响应,如 HTTP 请求。
- 数据库操作:查询或写入数据库的过程,这些操作通常涉及网络通信和磁盘访问。
与 CPU 密集型任务的对比
- I/O 密集型任务:主要依赖于 I/O 操作,CPU 通常在执行期间处于等待状态。
- CPU 密集型任务:主要依赖于计算和处理,通常会占用大量的 CPU 资源。
处理 I/O 密集型任务的方式
- 采用 异步编程:如使用回调或 Promises 来处理 I/O 操作,而不是阻塞主线程。
- 利用 多线程或多进程:同时处理多个 I/O 操作,以减少整体等待时间。
总结
I/O 密集型任务是在执行中高度依赖于数据交换和处理速度的任务。理解 I/O 密集型任务的概念有助于在设计和优化系统时选择合适的编程模型和架构。
因为爬虫主要就是和网络进行交互,不太消耗我们自己电脑的CPU,负责接收网路返回的数据,是一种写入操作,就是适合爬虫
创建并使用协程
asyncio模块
python的标准库
- 创建协程函数
async def function()
await IO操作 - 调用协程函数
async def main()
await function() - 并发执行多个协程:
asyncio.create task() - 运行协程:
asyncio.run(main())
import asyncio # 导入模块
import time# 创建协程函数
async def singing():print('start singing')time.sleep(2)print('end singing')async def dancing():print('start dance')time.sleep(3)print('end dance')async def main():# 调用协程函数await singing()await dancing()if __name__ == '__main__':start_time = time.time()# 运行协程函数asyncio.run(main())end_time = time.time()print(f'time:{end_time-start_time}')start singing
end singing
start dance
end dance
time:5.002954006195068
发现是5秒,就是串行
上面的这个程序是协程程序,但是是单协程,也就是串行,一个一个来
创建协程函数
asyncio.create_task(singing())
await asyncio.wait([task1,task2])
import asyncio # 导入模块
import time# 创建协程函数
async def singing():print('start singing')await asyncio.sleep(2)print('end singing')async def dancing():print('start dance')await asyncio.sleep(3)print('end dance')async def main():# 使用协程里面的任务函数,来创建并发多协程task1 = asyncio.create_task(singing())task2 = asyncio.create_task(dancing())await asyncio.wait([task1,task2])if __name__ == '__main__':start_time = time.time()# 运行协程函数asyncio.run(main())end_time = time.time()print(f'time:{end_time-start_time}')start singing
start dance
end singing
end dance
time:3.0030245780944824
和多线程一样,都是有一个模块自己的函数,来启动线程/协程
time是一个同步函数,不能让CPU异步执行,即便是使用了并发执行多任务函数,CPU也不能同时运行
使用await调用协程函数自带的sleep函数
CPU遇到await语句,并且发生了堵塞,比如网络请求还没到,或者这个sleep等待函数未执行完,CPU都会自己切换出去
运行协程函数asyncio.run(main())
import asyncio # 导入模块
import time# 创建协程函数
async def singing():print('start singing')await asyncio.sleep(2)print('end singing')async def dancing():print('start dance')await asyncio.sleep(3)print('end dance')async def main():# 和多线程一样,可以把要启动的多协程任务放到一个列表里面,最后在启动列表task = []for i in range(3):task.append(asyncio.create_task(singing()))task.append(asyncio.create_task(dancing()))await asyncio.wait(task) # 启动协程 if __name__ == '__main__':start_time = time.time()# 运行协程函数asyncio.run(main())end_time = time.time()print(f'time:{end_time-start_time}')start singing
start dance
start singing
start dance
start singing
start dance
end singing
end singing
end singing
end dance
end dance
end dance
time:3.003164768218994
和多线程一样,先是用asyncio模块下面的create task也就是字面意思,创建一个多协程任务,把协程函数写在里面
外面使用for循环,控制循环次数,也就是协程的数量,每循环一次,就会在这个create task里面多两个任务
所以循环了三次,就有6个任务被创建
因为这是协程任务,里面的sleep就是阻塞,所以程序一直在切换协程
aiohttp模块
相当于异步requests模块,适合在协程中使用使用方法类似 requests模块
官网:https://docs.aiohttp.org/en/stable/client_quickstart.html

requests是同步模块在协程中不能及时的释放CPU,所以需要使用协程专用的aiohttp模块
调用aiohttp模块步骤
- async with 是关键字
- aiohttp.ClientSession() 这是一个方法,然后起名字
- async with aiohttp.ClientSession() as session:
- async with session.get(url) as r: 前面两个是关键字,后面的是请求方式,和requests.get()一样
- 返回方式有三种:text,content,json
- 这里打印返回值的时候还要在后面加一个括号,r.text(),r.centent.read(),调用centent的时候还要加一个read()后缀,r.json()
import asyncio
import aiohttpasync def downloads(url):# print(url)name = url.split('/')[-1]# print(name)async with aiohttp.ClientSession() as session:async with session.get(url) as r: # 这里是把得到的网络请求内容赋值给rwith open(fr'E:\python笔记\{name}','wb') as f:f.write(await r.content.read()) # 这里需要使用等待关键字,因为是网络请求,网络响应的速度比不上CPU运算的速度print(f'已完成……{name}')async def main():urls = ('https://i1.huishahe.com/uploads/allimg/202302/9999/bcc80e5d24.jpg','https://i1.huishahe.com/uploads/allimg/202302/9999/8ccff5510c.jpg','https://i1.huishahe.com/uploads/allimg/202302/9999/186094180f.jpg')task = []for url in urls:task.append(asyncio.create_task(downloads(url))) # 把协程任务存进列表await asyncio.wait(task) # 启动列表内的任务,并告诉协程这是一个等待语句if __name__ == '__main__':asyncio.run(main())
设计思路:
- 设计协程函数入口
- 把协程函数写入协程任务
- 使用await 运行协程任务
- 设计协程函数
- async with aiohttp.ClientSession() as session这个是aiohttp的方法,必须要写
- async with session.get(url) as r 这个就是异步网络请求了,返回内容在r里面
aiofiles————协程异步函数
也是协程里面的函数,也是异步函数,可以主动等待网络的返回值
import asyncio
from os import write
import aiofiles
import aiohttpasync def downloads(url):# print(url)name = url.split('/')[-1]# print(name)async with aiohttp.ClientSession() as session:async with session.get(url) as r: # 这里是把得到的网络请求内容赋值给r# with open(fr'E:\python笔记\{name}','wb') as f:# f.write(await r.content.read()) # 这里需要使用等待关键字,因为是网络请求,网络响应的速度比不上CPU运算的速度# print(f'已完成……{name}')async with aiofiles.open(fr'E:\python笔记\{name}','wb') as f:await f.write(await r.content.read())print(f'已完成……{name}')
和原来的文件保存方式相似,就是换了个关键字
- 因为要使用协程函数,所以要使用async关键字
- 因为网络请求需要等待,可能阻塞,还要写await让程序挂起
遇到的问题
一 await asyncio.wait(task)的作用
在使用 Python 的 asyncio 库时,协程的调度和执行是通过事件循环来处理的。await asyncio.wait(task) 是用来等待一组任务完成的关键工具。下面是它的重要性和工作原理的详细解释:
1. 理解 await 的作用
await用于暂停协程的执行,直到被await的任务完成。它允许事件循环在等待的同时执行其他任务,从而提高效率。- 在
async函数中, 使用await的时候,协程会被挂起,控制权返回到事件循环,从而允许其他协程运行。
2. asyncio.wait(task) 的作用
asyncio.wait是一个并发等待工具,它接受一个任务或任务列表,直到这些任务中的一个或全部完成。它返回一个集合,包含已完成和未完成的任务,方便后续处理。- 通过等待任务的完成,我们可以获得每个任务的结果或获取异常信息。
3. 启动多个任务
- 使用
asyncio.wait启动和管理多个协程任务。例如,当有多个协程需要并发执行时,可以将它们封装在一个任务列表中,然后调用asyncio.wait来调度。 - 这样可以让我们更好地控制任务的执行,以及处理结果和异常。
多协程案例——爬取图片
效果图


完整代码
import pprintimport aiofiles
import aiohttp
import asyncio# 使用BS4解析网页
from bs4 import BeautifulSoup
from requests.packages import target# 获取翻页地址
async def get_all_url(url):# print(url)async with aiohttp.ClientSession() as session:async with session.get(url) as r:# print(await r.text()) # 可等待对象-----网页源代码soup = BeautifulSoup(await r.text(),'html.parser')links = soup.find('div',class_='slist').find_all('a',target="_blank") # 从目录页得到的总链接return_links = []for link in links:return_links.append(link['href'])return return_links# 获取目录页图片地址
async def get_url(url):# print(url)async with aiohttp.ClientSession() as session:async with session.get(url) as r:soup = BeautifulSoup(await r.text(), 'html.parser')pic_address = soup.find('div',class_="photo-pic").find('img')['src']title = soup.find('div',class_="photo-pic").find('img')['title']# print(pic_address,title)return pic_address,title# 下载图片
async def download_pic(jpg_address,title):# print(jpg_address,title)async with aiohttp.ClientSession() as session:async with session.get(jpg_address) as r:# print(r) # okasync with aiofiles.open(fr'E:\python笔记\{title}.jpg','wb') as f:await f.write(await r.content.read())print(f'已完成……{title}')async def main():task1 = []for i in range(1,2):if i == 1:url = 'https://www.moyublog.com/hdwallpapers/meinv/index.html'else:url = f'https://www.moyublog.com/hdwallpapers/meinv/index_{i}.html'task1.append(asyncio.create_task(get_all_url(url)))dones,pending = await asyncio.wait(task1) # await 关键字会返回两个内容,第一个是在函数里面return的# for link in dones: # 这里的dones返回的是一个列表,在改变目录页数的时候,列表的数量也会改变# print(link.result()) # 当你发起异步操作时,该操作可能尚未完成。任务对象在执行完成前只是一个占位符。只有在它们完成后,调用 result() 才能获取实际的返回值。# 不调用 result() 直接打印任务对象,会返回任务的信息(如状态),而不是实际的返回值。task2 = []for link in dones:pages = link.result() # 把一个列表储存在pages里面for rt in pages: # 这里是在使用rt读取一个pages列表,最后打印出来# print(rt) # 发现得到网页正常task2.append(asyncio.create_task(get_url(rt)))dones,pending = await asyncio.wait(task2)task3 = []for t in dones:# print(t.result()) # 发现返回的内容都在元组里面jpg_address,title = t.result() # 可以直接自定义两个参数接收元组里面的内容# print(jpg_address,title) # oktask3.append(asyncio.create_task(download_pic(jpg_address,title)))await asyncio.wait(task3)if __name__ == '__main__':asyncio.run(main())
设计思路
- 找个比较合适的网站
- 找个你感兴趣的分类
- 获取目录页网址,自己找规律组合其他的目录页
- 获取目录页里面的每一种图片网址
- 从图片的网址找到图片的链接
- 下载并保存图片
按顺序解读代码
先要清楚,这里是多协程代码,会有网络请求等语句,也就是程序堵塞的地方,都要使用aio的关键字,比如异步网络请求aiohttp,异步文件储存aiofiles,异步函数执行async,异步函数的运行asyncio.wait,还有异步任务的创建asyncio.creata_task()
- 找目录页里面的图片链接的时,首先按照aiohttp.ClientSession()的方法,创建session,在使用sesssion.get的方式向网络发送请求,这里的session.get的用法和requests.get一样
- 在上一步已经把返回的内容储存在对象r里面了
- 这里使用了BS4的语法进行文件解析,也算是练习一下BS4的语法
- 在这里获取到了图片页的链接
我们获得了图片页的链接和名称,这个协程的任务就结束了,现在我们把这两个内容返回出去
这是一个协程函数,它的返回内容有两个dones和pending,前者是已完成的内容,后者是未完成的内容
想要正常获取协程函数的返回值,我们需要使用这两个参数结束返回值,后面的参数不用管
我们对前面的参数使用result()方法解析,就可以正常获取内容了
这里我们得到了很多列表,也就是一个目录页里面的所有链接在一个列表里面
把这个列表传递给下一个函数get_url这个函数的工作是专门从图片页的链接得到图片的jpg文件和名称
同样也是协程函数,和上面的处理方式一样
再把图片的jpg链接和名称给下载及保存图片的函数,这里就使用了异步文件保存的方式,因为网络请求有一定的延迟,还要使用await关键字
主函数
我们使用for循环构造目录页的链接,并存入协程任务
然后是把链接给处理目录页的函数
再把返回内容给图片页函数
再把返回内容给下载图片的函数
这些都是异步协程操作,也就是I/O密集型任务
所以可以在极短的时间保存大量的图片,比之前的多线程快了很多
await 在 asyncio.wait 中并不会直接返回 dones 和 pendings 两个参数。相反,await asyncio.wait(...) 返回的是一个包含两个集合的元组:
done: 包含所有已完成的 Task 对象。pending: 包含所有未完成的 Task 对象。
研究的好几天才能较为熟练的使用协程函数,就是比较麻烦,但是因为是异步加载的请求,所以可以不用在等待网络返回内容时一直占用CPU了,CPU会去执行其他的协程
相关文章:
python项目实战——多协程下载美女图片
协程 文章目录 协程协程的优劣势什么是IO密集型任务特点示例与 CPU 密集型任务的对比处理 I/O 密集型任务的方式总结 创建并使用协程asyncio模块 创建协程函数运行协程函数asyncio.run(main())aiohttp模块调用aiohttp模块步骤 aiofiles————协程异步函数遇到的问题一 await …...
基于.NET 8.0,C#中Microsoft.Office.Interop.Excel来操作office365的excel
开发环境: Visual Studio 2022 office365 项目模板:WPF应用程序 框架:.NET 8.0 依赖:Microsoft.Office.Interop.Excel 注意: 1.使用Microsoft.Office.Interop.Excel库时,服务器或电脑里面必须安装得…...
使用无线方式连接Android设备进行调试的两种方法
1.使用配对码配对设备方式 手机(或者平板等安卓设备)和电脑需连接在同一WiFi 下;保证 SDK 为最新版本(adb --version ≥ 30.0.0); step1.手机启用开发者选项和无线调试模式(会提示确认ÿ…...
Valgrind的使用
Valgrind 是一个强大的开源工具,用于检测程序中的内存错误、内存泄漏以及线程问题。它广泛应用于 C/C++ 等需要手动管理内存的编程语言中。以下内容将详细介绍 Valgrind 的安装、基本使用方法、常用命令及其输出结果的解析。 1. 什么是 Valgrind? Valgrind 是一个用于内存调…...
微信小程序瀑布流实现,瀑布流长度不均等解决方法
这是一开始实现的瀑布流,将数据分为奇数列和偶数列 <view class"content-left"><block wx:for"{{list}}" wx:key"list"><template isitem-data data{{...item}} wx:if"{{index % 2 0}}"></template&…...
Notepad++通过自定义语言实现日志按照不同级别高亮
借助Notepad的自定义语言可以实现日志的按照不同级别的高亮; 参考: https://blog.csdn.net/commshare/article/details/131208656 在此基础上做了一点修改效果如下: xml文件: <NotepadPlus><UserLang name"Ansibl…...
2024年四川省大学生程序设计竞赛 补题记录
文章目录 Problem A. 逆序对染色(思维树状数组)Problem B. 连接召唤(贪心)Problem E. L 型覆盖检查器(模拟)Problem F. 小球进洞:平面版(几何)Problem G. 函数查询Proble…...
17_事件的处理
目录 绑定事件与解绑事件优化事件的绑定和解绑方式处理不同事件类型的绑定处理同一事件类型多个事件处理函数事件冒泡与更新时机问题 绑定事件与解绑事件 既然要处理事件,那么首先面临的问题是如何在 vnode 中描述这个事件,在 vnode.props 中࿰…...
1FreeRTOS学习(队列、二值信号量、计数型信号量之间的相同点和不同点)
相同点: (1)传递区间 队列、二值信号量、计数型信号量均可用在任务与任务,任务与中断之间进行消息传递 (2) 传递方式 创建队列--发送队列--接受队列 创建二值信号量--发送二值信号量--接受二值信号量 创建计…...
数据库设计与范式及其应用
数据库设计是数据库管理系统(DBMS)中的核心环节,良好的数据库设计不仅可以提高数据存取的效率,还能增强数据的可维护性和一致性。范式(Normalization)是一种设计原则,用于减少数据冗余和提高数据…...
笔记-配置PyTorch(CUDA 12.2)
文章目录 前言一、安装 PyTorch(CUDA 12.2)1. 创建并激活 Conda 环境2. 安装 PyTorch(CUDA 12.2)3. 安装 torch_geometric 及依赖项4. 验证安装 总结 前言 一、安装 PyTorch(CUDA 12.2) 1. 创建并激活 Con…...
[C++]——红黑树(附源码)
目录 一、前言 二、正文 2.1 红黑树的概念 2.2 红黑树的性质 2.3红黑树节点的定义 2.4 红黑树的插入 2.4.1 情况一 2.4.2 情况二 编辑 2.4.3 情况三 2.5 红黑树的验证 三、全部代码 四、结语 一、前言 在上一篇博客中,为小伙伴们进行了AVL树的讲解&#…...
网络文件系统搭建
在CentOS7上搭建网络文件系统(NFS),并让客户端进行挂载,具体步骤如下: 1. 服务器端操作 安装NFS服务器软件包: 执行以下命令安装NFS服务: sudo yum install nfs-utils -y 启动并启用NFS服务&…...
基于vue、VantUI、django的程序设计
首先构建vue项目,构建项目点这里 安装 npm install axios axios简介 Axios 是一个基于 promise 的 HTTP 库,用于发起请求和接收响应,实现异步操作 基本使用 axios对象 请求响应拦截 在utils文件夹里新建ajax.js 创建一个axios对象并…...
京准电钟解读:NTP网络对时服务器助力厂区改造方案
京准电钟解读:NTP网络对时服务器助力厂区改造方案 京准电钟解读:NTP网络对时服务器助力厂区改造方案 1)系统概述 时钟系统可通过网络进行管理及时间校对,为厂区提供高精度、全天时、全天候 的授时服务,统一全厂各种系统…...
本地docker-compose仓库搭建以及推送docker镜像到仓库
前言 以下部分知识只适用于linux,不适合小白,请自行甄别执行 1.搭建 #参考 https://blog.csdn.net/u011535199/article/details/107457275 version: 3 services:registry:restart: alwaysimage: registry:2ports:- 5000:5000environment:#REGISTRY_HT…...
WPF+MVVM案例实战(八)- 自定义开关控件封装实现
文章目录 1、案例运行效果2、项目准备2、功能实现1、控件模板实现2、控件封装1、目录与文件创建2、各文件功能实现 3、开关界面与主窗体菜单实现1、开关界面实现2、主窗体菜单实现 4、源代码获取 1、案例运行效果 2、项目准备 打开项目 Wpf_Examples,新建ToggleBut…...
单机kafka性能需要高性能的硬件做支撑
一般来说,单机kafka在硬件支持的情况下,能支持每秒100万写入,如果硬件没有那么好的话(机械硬盘,容器内给内存8G, CPU也不是很好),就只能减少每秒的写入量,每秒写入5万都比较不错了。 如果强行每…...
Spark 的 Http Broadcast 和 Torrent Broadcast 广播实现类的对比
在 Apache Spark 中,广播机制用于高效地将小型只读数据分发到集群中的各个执行器(Executor)。Spark 中主要有两种不同的广播实现方式:Http Broadcast 和 Torrent Broadcast。这两种方式的核心目标都是将数据高效地分发给所有工作节…...
030_Subplot_In_Matlab中多图绘制之subplot函数
基于子图的多图方法 专业的论文中通常涉及到多个有逻辑关系的图拼接在一起,构成相互支持或者对照。所以很早之前,Matlab就有这个子图的函数subplot。 这个函数的基本语义有三类: 在图窗上划分出一个矩形区域建立一个坐标系,并指…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
