Python编程异步爬虫——协程的基本原理

Python编程之异步爬虫

协程的基本原理

要实现异步机制的爬虫,自然和协程脱不了关系。

  1. 案例引入

先看一个案例网站,地址为https://www.httpbin.org/delay/5,访问这个链接需要先等5秒钟才能得到结果,这是因为服务器强制等待5秒时间才返回响应。下面来测试一下,用requests写一个遍历程序,直接遍历100次案例网站,看看效果,代码如下:

import requests
import logging
import timelogging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s:%(message)s')TOTAL_NUMBER = 100
URL = 'https://www.httpbin.org/delay/5'
start_time = time.time()
for _ in range(1, TOTAL_NUMBER + 1):logging.info('scraping %s', URL)response = requests.get(URL)end_time = time.time()
logging.info('total time %s seconds', end_time - start_time)

使用的是requests单线程,在爬取之前和爬取之后分别记录了时间,最后输出了爬取100个页面消耗的总时间。运行结果如下:

2024-03-23 18:45:12,159 - INFO:scraping https://www.httpbin.org/delay/5
2024-03-23 18:45:18,693 - INFO:scraping https://www.httpbin.org/delay/5
2024-03-23 18:45:24,865 - INFO:scraping https://www.httpbin.org/delay/5
2024-03-23 18:45:30,957 - INFO:scraping https://www.httpbin.org/delay/5
2024-03-23 18:45:37,544 - INFO:scraping https://www.httpbin.org/delay/5
….
….

2024-03-23 18:55:19,929 - INFO:scraping https://www.httpbin.org/delay/5
2024-03-23 18:55:26,069 - INFO:scraping https://www.httpbin.org/delay/5
2024-03-23 18:55:32,186 - INFO:total time 620.0276908874512 seconds

由于每个页面至少等待5秒钟,100个页面至少花费500秒,加上网站本身负载问题,总时间大约620秒,10分钟多。

  1. 基础知识

协程的基础概念

1. 阻塞和非阻塞:

  • 阻塞:当一个任务执行时,如果需要等待某个操作完成才能继续执行,这个任务就会被阻塞。在阻塞状态下,任务无法执行其他操作。
  • 非阻塞:相对于阻塞,非阻塞任务在等待某个操作完成时,可以继续执行其他操作。

2. 同步和异步:

  • 同步:指的是程序按照代码顺序依次执行,一个操作完成之后才会进行下一个操作。
  • 异步:异步编程允许程序在等待某个操作的同时继续执行其他操作,操作完成后通过回调或者事件通知来处理结果。

3. 多进程和协程:

  • 多进程:每个进程有自己独立的内存空间,系统为每个进程分配资源,进程间通信开销较大。
  • 协程:协程(coroutine)是一种轻量级的线程,可以看作是在同一个线程内部进行切换执行不同任务,共享同一个进程的资源,更高效利用 CPU 和内存。

协程的特点:

  • 轻量级: 协程不需要像线程那样创建新的进程或者线程,因此比多线程的切换开销更小。
  • 灵活性: 协程可以根据需要暂停和恢复执行,可以实现任务的合理调度。
  • 高效性: 由于不需要进行系统调用、进程/线程切换,协程可以更高效地利用计算资源。

在 Python 中,使用 asyncio 库可以实现协程。通过 asyncawait 关键字可以定义异步函数和阻塞点,在适当的时机挂起和恢复函数的执行。

协程的优点在于它们可以解决异步编程中的并发性问题,并且能够提供更好的性能和资源利用率。通过合理地使用协程,可以实现高效的并发编程,尤其在 I/O 密集型应用中表现突出。

  1. 协程的用法

    在 Python 中,可以使用 asyncio 库来实现协程。以下是协程的基本用法示例:

    1. 定义一个异步函数

    使用 async def 关键字定义一个异步函数,该函数可以包含 await 表达式来挂起执行。

    import asyncioasync def greet():print("Hello")await asyncio.sleep(1)print("World")

    b. 运行协程任务

    使用 asyncio.run() 函数来运行协程任务,并且保证事件循环的创建和销毁。

    asyncio.run(greet())

    c. 创建并发任务

    使用 asyncio.create_task() 函数创建多个并发任务,让它们同时运行。

    async def task1():print("Task 1 start")await asyncio.sleep(2)print("Task 1 end")async def task2():print("Task 2 start")await asyncio.sleep(1)print("Task 2 end")async def main():taskA = asyncio.create_task(task1())taskB = asyncio.create_task(task2())await taskAawait taskBasyncio.run(main())

    d. 并发等待多个任务完成

    使用 asyncio.gather() 函数等待多个任务完成后再继续执行。

    async def main():tasks = [task1(), task2()]await asyncio.gather(*tasks)asyncio.run(main())

    e. 异步IO操作

    在协程中可以进行异步的IO操作,例如网络请求、文件读写等操作,以提高应用程序的性能和效率。

    通过上述示例,您可以了解到如何定义、运行和管理协程,以及如何利用协程来处理并发任务和异步IO操作。在实际应用中,协程可以帮助降低资源消耗,提高程序响应性,并简化复杂的并发编程任务。

  2. 定义协程

    import asyncioasync def execute(x):print('Number:', x)coroutine = execute(1)
    print('Coroutine:', coroutine)
    print('After calling excute')loop = asyncio.get_event_loop()
    loop.run_until_complete(coroutine)
    print('After calling loop')运行结果如下:
    Coroutine: <coroutine object execute at 0x10f5b37c0>
    After calling excute
    Number: 1
    After calling loop
    

    导入asyncio包,这样才可以使用async和await关键字。然后使用async定义一个execute方法,该方法接收一个数字参数x,执行之后会打印这个数字。

    随后直接执行execute方法,然而这个方法没有执行,而是返回了一个coroutine协程对象。之后我们使用了get_event_loop方法创建了一个事件循环loop,调用loop对象的run_until_complete方法将协程对象注册到了事件循环中,接着启动。可见,async定义的方法会变成一个无法直接执行的协程对象,必须将此对象注册到事件循环中才可以执行。

    当我们把协程对象coroutine传递给run_until_complete方法的时候,实际上它进行了一个操作,就是将coroutine封装成task对象。显示声明,代码如下:

    import asyncioasync def execute(x):print('Number:', x)return xcoroutine = execute(1)
    print('Coroutine:', coroutine)
    print('After calling execute')loop = asyncio.get_event_loop()
    task = loop.create_task(coroutine)
    print('Task:',task)
    loop.run_until_complete(task)
    print('Task:', task)
    print('After calling loop')运行结果如下:
    Coroutine: <coroutine object execute at 0x10faf37c0>
    After calling execute
    Task: <Task pending name='Task-1' coro=<execute() running at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/协程用法4.py:3>>
    Number: 1
    Task: <Task finished name='Task-1' coro=<execute() done, defined at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/协程用法4.py:3> result=1>
    After calling loop
    

    定义task对象还有另外一种方法,就是直接调用asyncio包的ensure_future方法,返回结果也是task对象,写法如下:

    import asyncioasync def execute(x):print('Number:', x)return xcoroutine = execute(1)
    print('Coroutine:', coroutine)
    print('After calling execute')task = asyncio.ensure_future(coroutine)
    print('Task:', task)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(task)
    print('Task:', task)
    print('After calling loop')运行结果如下:
    Coroutine: <coroutine object execute at 0x10c3737c0>
    After calling execute
    Task: <Task pending name='Task-1' coro=<execute() running at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/协程用法5.py:3>>
    Number: 1
    Task: <Task finished name='Task-1' coro=<execute() done, defined at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/协程用法5.py:3> result=1>
    After calling loop
    
  3. 绑定回调

    为某个task对象绑定一个回调方法,如下所示:

    import asyncio
    import requestsasync def request():url = 'https://www.baidu.com'status = requests.get(url)return statusdef callback(task):print('Status:', task.result())coroutine = request()
    task = asyncio.ensure_future(coroutine)
    task.add_done_callback(callback)
    print('Task:', task)loop = asyncio.get_event_loop()
    loop.run_until_complete(task)
    print('Task:', task)
    

    定义了request方法,在这个方法里请求了百度,并获取了其状态码,随后我们定义了callback方法,这个方法接收一个参数,参数是task对象,在这个方法中调用print方法打印出task对象的结果。这样就定义好了一个协程对象和一个回调方法,我们希望达到的效果是,当协程对象执行完毕后,就去执行声明的callback方法。如何关联的呢?只要调用add_done_callback方法就行。将callback方法传递给封装好的task对象。这样当task执行完之后,就可以调用callback方法了。同时task对象还会作为参数传递给callback方法,调用task对象的result方法就可以获取返回结果了。运行结果如下:

    Task: <Task pending name='Task-1' coro=<request() running at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/绑定回调.py:4> cb=[callback() at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/绑定回调.py:9]>
    status: <Response [200]>
    task: <Task finished name='Task-1' coro=<request() done, defined at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/绑定回调.py:4> result=<Response [200]>>
    

    实际上,即使不使用回调方法,在task运行完毕后,也可以直接调用result方法获取结果,代码如下:

    import asyncio
    import requestsasync def request():url = 'https://www.baidu.com'status = requests.get(url)return statuscoroutine = request()
    task = asyncio.ensure_future(coroutine)
    print('Task:', task)loop = asyncio.get_event_loop()
    loop.run_until_complete(task)
    print('Task:', task)
    print('Task Result:', task.result())运行结果如下:
    Task: <Task pending name='Task-1' coro=<request() running at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/绑定回调1.py:5>>
    Task: <Task finished name='Task-1' coro=<request() done, defined at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/绑定回调1.py:5> result=<Response [200]>>
    Task Result: <Response [200]>
    
  4. 多任务协程

    如果想执行多次请求,应该怎么办?可以定义一个task列表,然后使用asyncio包中的wait方法执行,如下所示:

    import asyncio
    import requestsasync def request():url = 'https://www.baidu.com'status = requests.get(url)return statustasks = [asyncio.ensure_future(request()) for _ in range(5)]
    print('Tasks:', tasks)loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))for task in tasks:print('Task Result:', task.result())运行结果如下:
    Tasks: [<Task pending name='Task-1' coro=<request() running at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/多任务协程.py:5>>, <Task pending name='Task-2' coro=<request() running at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/多任务协程.py:5>>, <Task pending name='Task-3' coro=<request() running at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/多任务协程.py:5>>, <Task pending name='Task-4' coro=<request() running at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/多任务协程.py:5>>, <Task pending name='Task-5' coro=<request() running at /Users/bruce_liu/PycharmProjects/崔庆才--爬虫/6章异步爬虫/多任务协程.py:5>>]
    Task Result: <Response [200]>
    Task Result: <Response [200]>
    Task Result: <Response [200]>
    Task Result: <Response [200]>
    Task Result: <Response [200]>
    
  5. 协程实现

    协程在解决IO密集型任务方面的优势,耗时等待一般都是IO操作,例如文件读取、网络请求等。协程在处理这种操作时是有很大优势的,当遇到需要等待的情况时,程序可以暂时挂起,转而执行其他操作,避免浪费时间。

    以https://www.httpbin.org/delay/5为例,体验一下协程的效果。示例代码如下:

    import asyncio
    import requests
    import timestart = time.time()async def request():url = 'https://www.httpbin.org/delay/5'print('waiting for', url)response = requests.get(url)print('Get response from', url, 'response', response)tasks = [asyncio.ensure_future(request()) for _ in range(10)]
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))end = time.time()
    print('Cost time:', end - start)运行结果如下:
    waiting for https://www.httpbin.org/delay/5
    Get response from https://www.httpbin.org/delay/5 response <Response [200]>
    waiting for https://www.httpbin.org/delay/5
    Get response from https://www.httpbin.org/delay/5 response <Response [200]>
    waiting for https://www.httpbin.org/delay/5
    Get response from https://www.httpbin.org/delay/5 response <Response [200]>
    ...
    waiting for https://www.httpbin.org/delay/5
    Get response from https://www.httpbin.org/delay/5 response <Response [200]>
    waiting for https://www.httpbin.org/delay/5
    Get response from https://www.httpbin.org/delay/5 response <Response [200]>
    waiting for https://www.httpbin.org/delay/5
    Get response from https://www.httpbin.org/delay/5 response <Response [200]>
    Cost time: 63.61974787712097
    

    可以发现,与正常的顺序请求没有啥区别。那么异步处理的优势呢?要实现异步处理,先得有挂起操作,当一个任务需要等待IO结果的时候,可以挂起当前任务,转而执行其他任务,这样才能充分利用好资源。

  6. 使用aiohttp

    aiohttp是一个支持异步请求的库,它和asyncio配合使用,可以使我们非常方便地实现异步请求操作。

    aiohttp分为两部分:一部分是Client,一部分是Server。

    下面我们将aiohttp投入使用,将代码改成如下:

    import asyncio
    import aiohttp
    import timestart = time.time()async def get(url):session = aiohttp.ClientSession()response = await session.get(url)await response.text()await session.close()return responseasync def request():url = 'https://www.httpbin.org/delay/5'print('Waiting for', url)response = await get(url)print('Get response from', url, 'response', response)tasks = [asyncio.ensure_future(request()) for _ in range(10)]
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))end = time.time()
    print('Cost time:', end - start)运行结果如下:
    Waiting for https://www.httpbin.org/delay/5
    Waiting for https://www.httpbin.org/delay/5
    Waiting for https://www.httpbin.org/delay/5
    Waiting for https://www.httpbin.org/delay/5
    Waiting for https://www.httpbin.org/delay/5
    Waiting for https://www.httpbin.org/delay/5
    ...
    Get response from https://www.httpbin.org/delay/5 response <ClientResponse(https://www.httpbin.org/delay/5) [200 OK]>
    <CIMultiDictProxy('Date': 'Sat, 23 Mar 2024 13:42:05 GMT', 'Content-Type': 'application/json', 'Content-Length': '367', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>Get response from https://www.httpbin.org/delay/5 response <ClientResponse(https://www.httpbin.org/delay/5) [200 OK]>
    <CIMultiDictProxy('Date': 'Sat, 23 Mar 2024 13:42:05 GMT', 'Content-Type': 'application/json', 'Content-Length': '367', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
    ...
    Get response from https://www.httpbin.org/delay/5 response <ClientResponse(https://www.httpbin.org/delay/5) [200 OK]>
    <CIMultiDictProxy('Date': 'Sat, 23 Mar 2024 13:42:05 GMT', 'Content-Type': 'application/json', 'Content-Length': '367', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>Get response from https://www.httpbin.org/delay/5 response <ClientResponse(https://www.httpbin.org/delay/5) [200 OK]>
    <CIMultiDictProxy('Date': 'Sat, 23 Mar 2024 13:42:05 GMT', 'Content-Type': 'application/json', 'Content-Length': '367', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>Cost time: 6.868626832962036
    

    这里将请求库由requests改成了aiohttp,利用aiohttp库里ClientSession类的get方法进行请求。

    测试一下并发量分别为1、3、5、10、….、500时的耗时情况,代码如下:

    import asyncio
    import aiohttp
    import timedef test(number):start = time.time()async def get(url):session = aiohttp.ClientSession()response = await session.get(url)await response.text()await session.close()return responseasync def request():url = 'https://www.baidu.com/'await get(url)tasks = [asyncio.ensure_future(request()) for _ in range(number)]loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))end = time.time()print('Number:', number, 'Cost time:', end - start)for number in [1, 3, 5, 10, 15, 30, 50, 75, 100, 200, 500]:test(number)运行结果如下:
    Number: 1 Cost time: 0.23929095268249512
    Number: 3 Cost time: 0.19086170196533203
    Number: 5 Cost time: 0.20035600662231445
    Number: 10 Cost time: 0.21305394172668457
    Number: 15 Cost time: 0.25495195388793945
    Number: 30 Cost time: 0.769071102142334
    Number: 50 Cost time: 0.3470029830932617
    Number: 75 Cost time: 0.4492309093475342
    Number: 100 Cost time: 0.586918830871582
    Number: 200 Cost time: 1.0910720825195312
    Number: 500 Cost time: 2.4768006801605225
    

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

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

相关文章

cookie、session和token的区别

引言 在当今的互联网时代&#xff0c;Web 应用程序的安全性和用户体验至关重要。身份验证和状态管理是构建安全、可靠的 Web 应用的核心部分。cookie、session、token都是常用的身份验证和状态管理机制。 Cookie 什么是 Cookie&#xff1f; Cookie 是存储在用户浏览器中的小…

【算法】回溯与深搜

方法论 1.构建决策树 2.设计代码&#xff1a;全局变量、dfs函数 3.剪枝&#xff0c;回溯 全排列 给定一个不含重复数字的整数数组 nums &#xff0c;返回其 所有可能的全排列 。可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff…

微软Microsoft Surface Go 2

1个小玩具 Microsoft Surface Go 2的评测结果出炉&#xff01;它是目前最好的中端Windows 二合一笔记本平板。 外形简洁小巧&#xff0c;工作娱乐两不误。 它有多个版本。 我们测试的是配备8GB Ram和128GB SSD的Pentium 4425Y处理器&#xff08;第8代&#xff09;的型号。 S…

elementary OS7 Ubuntu 22.04中硬盘挂载报错

elementary OS7 Ubuntu 22.04中硬盘挂载报错 背景目标思路解决方法 背景 上周末安装elementaryos7的过程中将windows10的引导文件搞丢了&#xff0c;这两天准备修复一下&#xff0c;保险期间将固态硬盘上的文件备份到移动硬盘上&#xff0c;备份过程中出现报错的问题&#xff…

机器学习的常用方法

引言&#xff1a; 机器学习&#xff08;Machine Learning&#xff0c;ML&#xff09;是一种以计算机程序为基础&#xff0c;在不需要明确编程的情况下&#xff0c;对数据进行分析和处理的人工智能技术。与传统的计算机编程相比&#xff0c;机器学习的区别在于它通过数据建立模…

对适配器模式的理解

目录 一、适配器模式是什么&#xff1f;二、示例【[来源](https://refactoringguru.cn/design-patterns/adapter)】1 第三方依赖 &#xff08;接口A 数据A&#xff09;2 客户端3 方钉转圆钉的适配器&#xff08;数据B&#xff09; 三、适配器&#xff08;xxxAdapter&#xff0…

超越肉眼:深入计算机视觉的奇妙之旅

揭秘计算机视觉的奥秘&#xff1a;从基础到前沿的探索之旅 引言&#xff1a;一、计算机视觉的基础1. 图像处理基础2. 特征提取与描述3. 基本模式识别 二、机器学习在计算机视觉中的应用1. 深度学习革命2. 迁移学习与多任务学习3. 强化学习与主动学习4. 无监督学习和自监督学习 …

C++ [COCI2017-2018#6] Davor

文章目录 一、题目描述[COCI2017-2018#6] Davor题面翻译题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 样例 #3样例输入 #3样例输出 #3 二、参考代码 一、题目描述 [COCI2017-2018#6] Davor 题面翻译 在征服南极之后&#xff0c;Da…

Kafka系列之:Kafka Connect REST API

Kafka系列之:Kafka Connect REST API 由于 Kafka Connect 旨在作为服务运行,因此它还提供了用于管理连接器的 REST API。此 REST API 可在独立模式和分布式模式下使用。可以使用侦听器配置选项来配置 REST API 服务器。该字段应包含以下格式的侦听器列表: protocol://host:p…

Axure RP 9 for Mac中文激活版:原型设计工具

Axure RP 9 for Mac是一款值得设计师信赖的原型设计工具。它以其卓越的性能和稳定的运行赢得了广大用户的赞誉。 软件下载&#xff1a;Axure RP 9 for Mac中文激活版下载 在Axure RP 9中&#xff0c;您可以尽情发挥自己的设计才华&#xff0c;创造出独一无二的原型作品。无论是…

电子电器架构 —— 诊断数据DTC起始篇(下)

电子电器架构 —— 诊断数据DTC起始篇(下) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶,喝完再…

系统架构设计-构建系统应用

1. 系统架构目标与设计原则 在设计系统架构时&#xff0c;我们的目标是确保系统具有以下特点&#xff1a; 可靠性&#xff1a;系统能够持续稳定运行&#xff0c;保证业务可用性。可伸缩性&#xff1a;系统能够根据负载变化自动扩展或收缩&#xff0c;以应对不同的流量需求。容…

STM32通过串口发送指令控制LED灯亮灭OLED并显示命令

先来看看程序运行的结果吧&#xff1a; 接下来就不说废话了&#xff0c;自己看源代码吧&#xff01;每一行我都做了注释&#xff1a; 首先是主函数main.c文件&#xff1a; #include "stm32f10x.h" // Device header #include "OLED.h" …

Python工具-清理Unity(批量深度)清理U3D项目工程保留关键工程文件

前沿 1. Unity工程越来越多&#xff0c;很久不用的工程里存在了很多无用的大文件夹&#xff0c;极大的影响电脑容量。 2. 我电脑里面U3D工程只有17个&#xff0c;但容量就高达60GB&#xff0c;使用自己编写的工具清理后&#xff0c;减到了30GB多。清理了不是很重要的文件和文件…

【CTA动画】制作全记录 笔记

3Dxchange的使用 让图片跳舞 导入&#xff1a;I:\安装包\#动画开发\test\跳舞 model(includeTPose).fbx 转成非标准角色 手动点击骨骼&#xff0c;然后点击人物骨骼&#xff0c;选择00_t-pose 绿灯了就可以转换了&#xff0c;记得启用。 上面的自定义可以先选择3DS 转换后…

Java数据结构-顺序表

目录 1. 顺序表的相关概念1.1 线性表1.2 顺序表2. 功能实现2.1 整体框架2.2 乱七八糟的功能(bushi)2.2.1 判断容量是否满2.2.2 返回顺序表当前长度2.2.3 扩容2.2.4 清空整个顺序表 2.3 插入数据2.3.1 头插数据2.3.2 尾插数据2.3.3 指定位置插入 2.4 删除数据2.4.1 删除第一次出…

微服务之Nacos配置管理

文章目录 前言一、统一配置管理Nacos操作二、统一配置管理java操作1.引入依赖2.创建配置文件3.测试4.总结 三、Nacos配置自动更新1.添加注解RefreshScope2.使用ConfigurationProperties注解3.总结 四、Nacos多环境配置共享1.配置文件2.多种配置的优先级3.总结 总结 前言 一、统…

leetcode 150.逆波兰表达式求值

题目 思路 逆波兰表达式也是经典的栈的应用问题。 先说什么是逆波兰表达式&#xff08;也叫后缀表达式&#xff09; 我们习惯的是这样的表达式&#xff1a;1 2 / 3 ,这也叫中缀表达式。 但是对于计算机来说不好理解&#xff0c;当从左扫描到 2 的时候还需要再判断2后面是什…

STM32 | Systick定时器(第四天源码解析)

STM32 | Systick定时器(第四天)STM32 | STM32F407ZE中断、按键、灯(续第三天)1、参考delay_us代码,完成delay_ms的程序 定时器频率换算单位:1GHZ=1000MHZ=1000 000KHZ = 1000 000 000HZ 定时器定时时间:计数个数/f(频率) 或者 (1/f(频率))*计数的个数 500/1MHZ = 500/1…

C++面向对象三大特征-----继承(详细版)

目录 继承 一、继承的基础介绍 普通版网页和继承版网页的区别 语法 二、继承方式 三种继承方式 三、继承中的对象模型 四、继承中构造和析构函数 五、继承同名成员的处理方式 访问同名成员&#xff1a; 作用域写法&#xff1a; 六、继承同名静态成员的处理方式 访问…