网络爬虫之多任务数据采集(多线程、多进程、协程)

进程:是操作系统中资源分配的基本单位

线程:使用进程分配的资源处理具体任务

一个进程中可以有多个线程:进程相当于一个公司,线程就是公司里面的员工。

一 多线程

多线程都是关于功能的并发执行。而异步编程是关于函数之间的非阻塞执行,我们可以将异步应用于单线程或多线程当中。多线程是与具体的执行者相关的,而异步是与任务相关的。

并发和并行

一个程序在计算机中运行,其底层是处理器通过运行一条条的指令来实现的。

并发

并发,英文叫作 concurrency。它是指同一时刻只能有一条指令执行,但是多个线程的对应的指令被快速轮换地执行。比如一个处理器它先执行线程A的指令一段时间,再执行线程 B 的指令一段时间,再切回到线程 A执行一段时间。
由于处理器执行指令的速度和切换的速度非常非常快,人完全感知不到计算机在这个过程中有多个线程切换上下文执行的操作,这就使得宏观上看起来多个线程在同时运行。但微观上只是这个处理器在连续不断地在多个线程之间切换和执行,每个线程的执行一定会占用这个处理器一个时间片段,同一时刻,其实只有一个线程在执行。

并行

并行,英文叫作 paralel。它是指同一时刻,有多条指今在多个处理器上同时执行,并行必须要依赖于多个处理器,不论是从宏观上还是微观上,多个线程都是在同一时刻一起执行的。
并行只能在多处理器系统中存在,如果我们的计算机处理器只有一个核,那就不可能实现并行。而并发在单处理器和多处理器系统中都是存在的,仅仅依靠一个核,就能实现并发。

总结:

当系统有一个以上CPU时,则线程的操作可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程不抢占CPU资源,可以同时进行,这种方式称之为并行(Parallel)

(一)单线程

import requests,time
import threadingdef test(url):resp = requests.get(url)  # 发送GET请求到指定的URL# 可以在这里处理响应,例如打印状态码或内容# print(resp.status_code)
if __name__ == '__main__':start = time.time()url = 'https://www.baidu.com'for i in range(10):test(url)resp = time.time()-startprint(resp,'单线程')

(二)多线程

import requests,time
import threadingdef test(url):resp = requests.get(url)  # 发送GET请求到指定的URL# 可以在这里处理响应,例如打印状态码或内容# print(resp.status_code)
if __name__ == '__main__':start = time.time()url = 'https://www.baidu.com'for i in range(10):test(url)resp = time.time()-startprint(resp,'单线程')if __name__ == '__main__':start1 = time.time()  # 记录当前时间用于后面计算总的运行时间url = 'https://www.baidu.com'threads = []  # 用于存储线程对象的列表# 创建并启动10个线程for i in range(10): #创建10个线程# 创建一个线程对象 target代表调用的函数 args代表给函数传递的参数thread = threading.Thread(target=test, args=(url,))  # 注意args是一个元组,即使只有一个元素threads.append(thread)  # 将线程加入到列表中thread.start()# 等待所有线程完成for thread in threads:thread.join() #意思是等所有的线程完成了再执行下面的操作elapsed_time = time.time() - start1  # 计算总的运行时间print(elapsed_time, '多线程')  # 打印多线程执行时间

(三)线程样例

# 导入 threading 和 time 模块
import threading, time
# 定义一个名为 target 的函数,它接受一个参数 second
def target(second):# 打印当前线程的名称和一条开始运行的消息print(f'Threading {threading.current_thread().name} is running')# 打印当前线程将要休眠的秒数print(f'Threading {threading.current_thread().name} sleep {second}s')# 使线程休眠指定的秒数time.sleep(second)# 打印当前线程结束的消息print(f'Threading {threading.current_thread().name} is ended')# 打印主线程正在运行的消息
print(f'Threading {threading.current_thread().name} is running')# 创建一个循环,循环值为列表 [1, 5] 中的元素
for i in [1, 5]:# 创建一个新的线程对象,目标函数是 target,参数是列表中的当前元素thread = threading.Thread(target=target, args=[i])# 启动新创建的线程thread.start()# 打印主线程已经结束的消息print(f'Threading {threading.current_thread().name} is ended')'''
输出
Threading MainThread is running
Threading Thread-1 is runningThreading MainThread is endedThreading Thread-1 sleep 1s
Threading Thread-2 is runningThreading MainThread is endedThreading Thread-2 sleep 5s
Threading Thread-1 is ended
Threading Thread-2 is ended
'''

(四)线程等待

# 导入 threading 和 time 模块
import threading, time
# 定义一个名为 target 的函数,它接受一个参数 second
def target(second):# 打印当前线程的名称和一条开始运行的消息print(f'Threading {threading.current_thread().name} is running')# 打印当前线程将要休眠的秒数print(f'Threading {threading.current_thread().name} sleep {second}s')# 使线程休眠指定的秒数time.sleep(second)# 打印当前线程结束的消息print(f'Threading {threading.current_thread().name} is ended')# 主线程退出,子线程才退出 会出问题
print(f'Threading {threading.current_thread().name} is running')t = []
# 创建一个循环,循环值为列表 [1, 5] 中的元素
for i in [1, 5]:# 创建一个新的线程对象,目标函数是 target,参数是列表中的当前元素thread = threading.Thread(target=target, args=[i])t.append(thread)# 启动新创建的线程thread.start()# 打印主线程已经结束的消息
for i in t:#这里面是线程1和线程2,主线程在外边i.join() # 作用 阻塞下
print(f'Threading {threading.current_thread().name} is ended')

(五)线程池

线程池,是一种线程的使用模式,它为了降低线程使用中频繁的创建和销毁所带来的资源消耗与代价。通过创建一定数量的线程,让他们时刻准备就绪等待新任务的到达,而任务执行结束之后再重新回来继续待命。

# 导入 ThreadPoolExecutor 类,这个类是 concurrent.futures 模块提供的一个高层接口
# 用于异步执行使用线程的调用
from concurrent.futures import ThreadPoolExecutor
# 打印出传入的 UR
def crawl(url):print(url)if __name__ =='__main__':base_url ='https://jobs.51job.com/pachongkaifa/p{}'# 使用with 语句和 ThreadPoolExecutor(10) 创建一个可以容纳 10 个线程的线程池。# with 语句的上下文管理特性确保线程池在执行完毕后会被正确关闭。with ThreadPoolExecutor(10) as f:# 创建1到14 14个数字表示页码for i in range(1,15):# 使用f.submit(crawl, url=base_url.format(i))提交一个任务给线程池# submit方法安排执行函数crawl,并传入格式化后的URL作为参数f.submit(crawl,url=base_url.format(i))

多线程采集实例--采集王者荣耀皮肤图片


'''
头像地址
'https://game.gtimg.cn/images/yxzj/img201606/heroimg/537/537-smallskin-3.jpg'
皮肤地址
'https://game.gtimg.cn/images/yxzj/img201606/skin/hero-info/537/537-bigskin-3.jpg'
露娜
https://game.gtimg.cn/images/yxzj/img201606/heroimg/146/146.jpg{"ename": 146,"cname": "露娜","id_name": "luna","title": "月光之女","new_type": 0,"hero_type": 1,"hero_type2": 2,"skin_name": "月光之女|哥特玫瑰|绯红之刃|紫霞仙子|一生所爱","moss_id": 3934}'''
import requests
import os
import json
import threading
import time
from lxml import etreeh = []
s = time.time()
def pa(j):num = j['ename']name = j['cname']res2 = requests.get('https://pvp.qq.com/web201605/herodetail/{}.shtml'.format(num))res2_decode = res2.content.decode('gbk')_element = etree.HTML(res2_decode)# 获取皮肤名称element_img = _element.xpath('.//div[@class="pic-pf"]/ul/@data-imgname')name_img= element_img[0].split('|')# 输出格式如下# ['正义爆轰&0', '地狱岩魂&12', '无尽征程&1', '寅虎·御盾&93']len1 = len(name_img)for i in range(0,10):res1 = requests.get('https://game.gtimg.cn/images/yxzj/img201606/skin/hero-info/{0}/{0}-bigskin-{1}.jpg'.format(num,i+1))if res1.status_code==200:try:aa = name_img[i].find('&')bb = name_img[i][:aa]except Exception as e:print(e)# 返回 如正义爆轰res_img = res1.content #将图片转换成二进制方便存储a = 'D:/桌面/王者荣耀/'+str(name)b = 'D:/桌面/王者荣耀/'+str(name)+'/'+bb+'.jpg'if not os.path.exists('D:/桌面/王者荣耀/'):os.makedirs('D:/桌面/王者荣耀/')if not os.path.exists(a):print(f'正在创建{name}文件夹')os.mkdir(a)with open(b,'wb') as f:f.write(res_img)print(name,bb)else:breakdef duo():resp = requests.get('https://pvp.qq.com/web201605/js/herolist.json')data = json.loads(resp.text)for j in data:t = threading.Thread(target=pa,args=(j,))t.start()h.append(t)for k in h:k.join()if __name__ == '__main__':duo()g = time.time()print("用时:",g-s)

二 多进程

参考文档:https://docs.python.org/zh-cn/3/library/multiprocessing.html

进程内置方法

run()

表示进程活动的方法。你可以在子类中重载此方法。标准run()方法调用传递给对象构造函数的可调用对象作为目标参数(如果有),分别从args和kwargs 参数中获取顺序和关键字参数。

start()

启动进程活动。这个方法每个进程对象最多只能调用一次。它会将对象的 run()方法安排在一个单独的进程中调用.

join(timeout)

如果可选参数 timeout是 one (默认值),则该方法将阻赛,直到调用 oin 方法的进程终止,如果 timeout是一个正数,它最多会阻塞 timeout秒,请注意,如果进程终止或方法超时,则该方法返回 None 。检查进程的 xitcode 以确定它是否终止。一个进程可以被join 多次。进程无法iin自身,因为这会导致死锁。尝试在启动进程之前ioin进程是错误的。

name()

进程的名称。该名称是一个字符串,仅用于识别目的。它没有语义。可以为多个进程指定相同的名称。初始名称由构造器设定。如果没有为构造器提供显式名称,则会造一个形式为Process-N1:N2:..Nk的名称,其中每个Nk 是其父亲的第 N 个孩子。

is_alive()

返回进程是否还活着。粗略地说,从 start()方法返到子进程终止之前,进程对象仍处于活动状态。

daemon

daemon 进程在 Python 的 multiprocessing 模块中有特殊的含义。它是一个指示该进程是否是守护进程的布尔标志。在计算机科学中,守护进程(或守护线程)一般指在后台运行的进程(或线程),它独立于控制终端,并且周期性地执行某种任务或等待处理某些发生的事件。然而,在 Python 的 multiprocessing 模块中,守护进程有点不同。

当你在一个 multiprocessing.Process 对象上设置 daemon = True 时,这意味着:

  1. 该进程是守护进程:该进程的生命周期不应比其父进程长。这意味着,当父进程结束时,守护进程也会被终止(不管守护进程是否完成了它的工作)。守护进程通常用于不需要明确停止的任务,因为它们会随着父进程的结束而自动停止。

  2. 在守护进程退出时,它的子进程也会被终止:守护进程不能创建子进程,如果尝试创建那将会抛出异常。这是为了防止产生孤儿进程,即当守护进程被终止时,它的子进程仍在运行,但没有任何进程管理它们。

  3. 它们不是 Unix 守护进程:在 Unix 中,守护进程是一个在后台运行的服务进程,通常在系统启动时启动,并直到系统关闭时才终止。Python 的守护进程不是这样的服务进程,而只是普通的进程,只不过它的生命周期受到父进程的控制。

  4. 它们在父进程退出后不会被操作系统的任何初始化系统“收养”:这意味着守护进程不会继续在后台运行,一旦父进程结束,守护进程也就结束了。

  5. 被终止的守护进程不会有机会进行资源清理:例如,打开的文件不会被正确关闭,所以使用守护进程时要小心。

如果你想要一个进程在父进程结束后继续运行,那么你不应该将它设置为守护进程。守护进程的典型用例是作为某种形式的服务提供者,其中服务在父进程运行时保持活动,但不需要在父进程结束后保持运行。

除了 threading.Thread API,Process 对象还支持以下属性和方法

pid

返回进程ID。在生成该进程之前,这将是 None。

(一)进程样例

import multiprocessingdef progress(index):print(f'Process:{index}')if __name__ == '__main__':for i in range(5):# 每循环一次,开启一个进程p = multiprocessing.Process(target=progress,args=(i,))p.start()

(二)进程等待

import multiprocessingdef progress(index):print(f'Process:{index}')if __name__ == '__main__':processes = []for i in range(5):# 每循环一次,开启一个进程p = multiprocessing.Process(target=progress, args=(i,))p.start()processes.append(p)  # 将进程添加到列表中for p in processes:p.join()  # 等待所有进程完成

(三)进程池

from multiprocessing import Pool
import requestsdef scrape(url):try:requests.get(url)print(f'URL- {url} -Scraped')requests.ConnectionError# 是在使用requests库进行HTTP请求时,如果在连接过程中遇到网络问题# (例如,DNS查询失败、拒绝连接等)时抛出的异常。except requests.ConnectionError :print(f'URL- {url} -not Scraped')if __name__ == '__main__':pool = Pool(processes=3)urls = ['https://www.baidu.com','http://www.meituan.com/','http://blog.csdn.net/','http://xxxyxxx.net']pool.map(scrape,urls)# for url in urls:# scrape(url)pool.close()

多进程爬取摩托信息

import requests
import multiprocessing
from multiprocessing import Pool
from lxml import etree
import pymysql
# maps1接收一个参数,然后根据X的值返回不同结果
# 1、如果X是一个非空序列(列表,元组,字符串等)返回序列第一个元素
# 2、如果X是一个空的序列或者None,返回X本身,此时是一个空的序列或None
maps1 = lambda x:x[0] if x else x  #通俗点 如果X不为空返回X[0],否则返回X
'''
xpath取值返回的是列表
如果使用[0]数据为空就会给程序报错
使用lambda表达式进行数据判断不为空才取值,为空就返回原值
'''
datas = []
def request(url):'''请求模块,负责网络请求'''headers = {'Cookie':'countsql=%5BS%5Fchexi%5Dwhere+1%3D1; fenyecounts=1218; ''Hm_lvt_f0b29a0b9bbbbaf0f3027855bba2f05a=1703216256; ''ASPSESSIONIDSESQSQAD=GDBEFCGCAPFOGEEOMJIAAIIB; ''Hm_lpvt_f0b29a0b9bbbbaf0f3027855bba2f05a=170323319','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'}try:res = requests.get(url,headers=headers)if res.status_code == 200:res.encoding = 'gb2312'parse(res.text)return res.textelse:res.raise_for_status()except requests.RequestException as e:print(f'请求出错信息是{e}')def parse_xpath(obj,tag):'''负责页面的数据解析工作'''# 将获得网页代码根据tag路径解析出想要的内容并返回html = etree.HTML(obj)text = html.xpath(tag)return text
def parse(res):'''总体业务:获取需要的数据'''url = '//ul[@class = "goods_list"]/li'items = parse_xpath(res,url)# html = etree.HTML(res)# items = html.xpath(url)for item in items:title = maps1(item.xpath('./p[@class="name"]/a/text()'))price = maps1(item.xpath('./p[@class="price_wrap"]//text()'))price = int(price[1:])# print({'品牌':title,'价格':price})# print('='*50)datas.append([title,price])for data in datas:save_date(data)
def mysql_conn():'''数据库连接模块'''db = pymysql.connect(host='localhost',user='root',password='123456',db='test1',port=3306)cuesor = db.cursor()return db,cuesordef save_date(data):'''保存数据模块'''db,cursor = mysql_conn()try:sql = 'insert into moto(name,price) values(%s,%s)'cursor.execute(sql,(data[0],data[1]))db.commit()except Exception as e:print(f'出错信息{e}')db.rollback()finally:cursor.close()db.close()
def run():'''入口函数开启任务多任务从这里面出发'''import times = time.time()url = 'https://www.2smoto.com/pinpai.asp'res = request(url)#获得总页数# # htmls = etree.HTML(res)# # html = maps1(htmls.xpath('.//div[@id="prolist"]/table//a[contains(text(),"尾页")]/@href'))[0]# # html = maps1(parse_xpath(res,'.//div[@id="prolist"]/table//a[contains(text(),"尾页")]/@href'))html = parse_xpath(res,'.//div[@id="prolist"]/table//a[contains(text(),"尾页")]/@href')if html:html = html[0]count = html.split('=')[-1]print(f'总共{count}页')else:print("没有获取到总页数")cpu_count = multiprocessing.cpu_count() #获取系统CPU数量print("CPU数量是:",cpu_count)pool = Pool(processes=cpu_count) # 创建进程数量等于cpu个数的进程池for i in range(1,int(count)+1):url = 'https://www.2smoto.com/pinpai.asp?ppt=&slx=0&skey=&page={}'.format(i)#开启多任务 每一条进程处理1个页面的数据pool.apply_async(request,(url,))pool.close()  #关闭进程池,关闭之后,不能再向进程池里面添加进程pool.join()  # 当进程池中所有的进程执行完毕后,主进程才能执行print(f'程序耗时{time.time()-s}s')if __name__ == '__main__':run()

三 异步协程

        我们知道爬虫是 I/O(输入输出) 密集型任务,比如如果我们使用 requests 库来爬某个站点,发出个请求之后,程序必须要等待网站返回响应之后才能接着运行,而在等待响应的过程中,整个爬虫程序是一直在等待的,实际上没有做任何的事情,对于这种情况我们有没有优化方案呢?

协程

在编程中,协程(Coroutine)是一种比线程更细粒度的计算运行单位,它是协作式多任务的子程序,可以在任何位置暂停或开始执行。与传统的多线程或多进程模型相比,协程提供了一种不同的并发执行机制。

以下是一些关键点来帮助理解协程:

  1. 自主性:协程与传统的函数调用不同,它们有自己的执行状态,包括调用位置、内部变量的状态和控制流程。这种状态在协程暂停时得以保留,在下一次恢复执行时可以使用。

  2. 协作式调度:协程执行可以在任意位置暂停,并在稍后恢复。它们不是被操作系统内核管理,而是完全由程序和程序员控制。这种暂停和恢复通常是显示的,通过关键字实现,例如 Python 中的 yieldawait

  3. 低开销:协程的开销比线程小得多,因为它们不需要线程的上下文切换。因此,创建数千甚至数百万个协程在资源上是可行的,而同样数量的线程可能会耗尽系统资源。

  4. 非抢占式:协程是非抢占式的,意味着它们不会像线程那样被操作系统强制从CPU上下文切换出去。相反,协程必须显式地交出控制权,这通常发生在 I/O 操作或通过特定的协程切换函数时。

基本概念

异步

为完成某个任务,不同程序单元之间过程中无需通信协调,也能完成任务的方式,不相关的程序单元之间可以是异步的。

例如,爬虫下载网页。调度程序调用下载程序后,即可调度其他任务,而无需与该下载任务保持通信以协调行为。不同网页的下载、保存等操作都是无关的,也无需相互通知协调。这些异步操作的完成时刻并不确定

同步

不同程序单元为了完成某个任务,在执行过程中需靠某种通信方式以协调一致,我们称这些程序单元是同步执行的。

阻塞

阻塞状态指程序未得到所需计算资源时被挂起的状态。

程序在等待某个操作完成期间,自身无法继续处理其他的事情,则称该程序在该操作上是阻塞的。

非阻塞

程序在等待某操作过程中,自身不被阻塞,可以继续处理其他的事情,则称该程序在该操作上是非阻塞的

同步/异步关注的是消息通信机制(synchronous communication/asynchronous communication)。阻塞/非阻塞关注的是程序在等待调用结果(消息,返回值)【是否有可用的资源】时的状态

同步执行流程图

异步执行流程图

(一)概念

使用之前需要先安装aiohttp库

pip install aiohttp

aiohttp 是一个基于 asyncio 的异步 HTTP 客户端/服务端框架,它允许你编写异步代码来处理 HTTP 请求。与传统的同步框架(如 Flask 或 Django)不同,aiohttp 适用于需要处理大量并发 HTTP 连接的情况,通过异步 I/O 编程模型提高性能。它既提供了服务端,又提供了客户端。其中我们用服务端可以搭建一个支持异步处理的服务器。
asvnc用来声明一个函数为异步函数
awat 用来声明程序挂起,比如异步程序执行到某一步时需要等待的时间很长,就将此挂起,去执行其他的异步程序

(二)同步
import time
import httpxdef main():with httpx.Client() as client:for i in range(50):res = client.get('https://www.example.com')print(f'第{i+1}次请求,响应状态码:{res.status_code}')if __name__ == '__main__':start = time.time()main()end =time.time()print(f'同步发送50次请求,耗时{start-end}秒')
(三)异步概念

异步函数是在现代编程中处理并发执行的一种方法,特别是在涉及到输入/输出(I/O)操作,如网络请求、文件系统操作等,这些操作往往是应用程序中延迟最大的部分。异步函数允许程序在等待这些长时间操作的过程中释放执行线程,以便可以处理其他任务。

在 Python 中,异步函数通常是指使用 async def 语法定义的函数。这些函数在调用时不会立即执行,而是返回一个协程对象。为了执行协程对象,你必须将它排入事件循环中。

import asyncio
import time
import httpx
async def req(client,i):res = await client.get('https://www.example.com')print(f'第{i+1}次请求,响应状态码:{res.status_code}')return res
async def main():async with httpx.AsyncClient() as client:task_lisk = []for i in range(50):res = req(client,i)task = asyncio.create_task(res)task_lisk.append(task)await asyncio.gather(*task_lisk)
if __name__ =='__main__':start = time.time()asyncio.run(main())end = time.time()print(f'异步发送50次请求,耗时{end-start}')

在这个例子中,req是一个异步函数,它使用await关键字暂停其执行,等待client.get(‘http://www/example.com’)执行完成。这允许其他协程在此期间运行,提高程序整体运行效率。

要运行这个异步函数,你需要使用 asyncio.run() 或其他机制来“驱动”事件循环

异步函数的关键优点包括:

  • 非阻塞行为:异步函数在遇到 await 时会暂停其执行,这让其他函数或协程可以在同一线程中运行。
  • 提高吞吐量:在 I/O 密集型应用程序中,可以同时处理多个 I/O 操作,这可以显著提高程序的吞吐量。
  • 改善用户体验:在 Web 应用程序中,异步函数可以提供更快的响应时间,从而改善用户体验。

在使用异步函数时需要注意:

  • 必须在支持异步操作的环境中使用异步函数,例如在由 asyncio 库提供的事件循环中。
  • 异步函数中的 await 表达式应该用于等待另一个异步函数或返回 awaitable 对象的操作(例如,由 asyncio 库提供的 I/O 函数)。
  • 编写异步代码需要一种不同的思维方式,因为不是所有的库都能在异步环境中工作,所以你可能需要寻找专门为异步编程设计的库。

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

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

相关文章

C语言——最古老的树

归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍 收藏⭐ 留言​📝 缺乏明确的目标,一生将庸庸…

drf知识--02

APIView执行流程分析 源码分析: # 1 在路由中:path(books/, views.BookView.as_view()),请求来了 # 2 先看 as_view()---->APIView的 as_view---》as_view执行结果跟之前一样,去除了csrf认证classmethoddef as_view(cls, **initkwargs):vi…

C# WPF上位机开发(文件对话框和目录对话框)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 一个上位机软件在处理数据的时候,除了配置文件、数据文件之外,一般还需要使用选择对话框进行文件和目录的选取。如果不这样…

20231222给NanoPC-T4(RK3399)开发板的适配原厂Android10的挖掘机方案并跑通AP6398SV

20231222给NanoPC-T4(RK3399)开发板的适配原厂Android10的挖掘机方案并跑通AP6398SV 1、简略步骤:rootrootrootroot-X99-Turbo:~/3TB/3399-android10$ cat Rockchip_Android10.0_SDK_Release.tar.gz0* > Rockchip_Android10.0_SDK_Release.tar.gz rootrootrootro…

C++进阶-继承

继承 一、继承的概念及定义1.1 继承的概念1.2 继承的定义1.2.1 定义格式1.2.2 继承关系和访问限定符1.2.3 继承基类成员访问方式的变化 二、基类和派生类对象赋值转换三、继承中的作用域3.1 同名成员变量3.2 同名成员函数 四、派生类的默认成员函数五、继承与友元六、继承与静态…

Leetcode—43.字符串相乘【中等】

2023每日刷题(六十八) Leetcode—43.字符串相乘 算法思想 实现代码 class Solution { public:string multiply(string num1, string num2) {int len1 num1.size(), len2 num2.size();string ans;int end1 len1 - 1, end2 len2 - 1;int arr[len1 l…

、写入Shellcode到注册表上线

其实本质就是将shellcode写入到注册表中,然后读取注册表中的shellcode,然后创建线程去执行shellcode。 如下图: 写入注册表shellcode 这里将shellcode写入到注册表中,在我们需要的时候再去读取然后执行。 这里用到如下两个Windows API函…

福FLUKE禄克8808A数字多用表

福禄克8808A,用于制造、研发、维修等应用的多功能数字表,FLUKE 8808A 5.5位数字多用表可以完成当今众多常用的测量工作。无论是功能测 展开 福禄克8808A,用于制造、研发、维修等应用的多功能数字表,FLUKE 8808A 5.5位数字多用表可…

【音视频】remb twcc原理

目录 twcc简介 WebRTC REMB 参考文档 twcc简介 TWCC全称是Transport wide Congestion Control,是webrtc的最新的拥塞控制算法。其原理是在接收端保存数据包状态,然后构造RTCP包反馈给发送端,反馈信息包括包到达时间、丢包状态等&#xff…

室内导航技术在智慧医疗的革新应用

随着科技的飞速发展,智慧医疗已经成为现代医疗服务的重要组成部分。在这个背景下,室内导航技术逐渐崭露头角,为智慧医疗建设带来了革命性的改变。本文将深入探讨室内导航技术在智慧医疗中的应用,并分析其为医疗服务带来的诸多便利…

vue:ref的作用和实例

定义:用来获取元素或子组件注册或者引用信息,父组件通过$ref获取到相应的DOM对象和子组件 1、vue中ref的作用 获取页面的DOM元素获取子组件的对象(也是一种通信方式) 2、实例 1、获取DOM,首先创建一个父页面index然…

如何自定义右键弹框并实现位置自适应?

一、问题 右键显示弹框,但是靠近浏览器边缘的部分会被隐藏,需要实现弹框位置自适应 二、 问题分析 如果想要最终弹框的宽高不超过屏幕视口,就等于屏幕视口的总宽/高减去弹框打开时的起点坐标,剩下的部分大于等于弹框的宽/高&…

商家如何进行商业模式开发,助力产品更好的销售模式?

商家如何进行商业模式开发,助力产品更好的销售模式? 随着各类电商平台的疯狂崛起,越来越多的商家对其中带来的高额回报率产生心动,毕竟对于线上的场景来说,即省去了房租、水电、仓储以及其他各种费用,用电商…

vue3 + TypeScript使用国际化

vue3 TypeScript使用国际化 本文使用了 Vite 构建工具创建的vue3项目Vite 支持使用特殊的 import.meta.glob 函数从文件系统导入多个模块Vite 官方中文文档当然如果你的vue3项目未使用vite,你也可以为你的旧项目提提速,安装vite ,安装方法在上一个博客…

【华为数据之道学习笔记】6-5数据地图的核心价值

数据供应者与消费者之间往往存在一种矛盾:供应者做了大量的数据治理工作、提供了大量的数据,但数据消费者却仍然不满意,他们始终认为在使用数据之前存在两个重大困难。 1)找数难 企业的数据分散存储在上千个数据库、上百万张物理表…

汽车行业一些知识

一、汽车术语集合 1、 轴距(mm):汽车前轴中心至后轴中心的距离。 2、转弯半径(mm):汽车转向时,汽车外侧转向轮的中心平面在车辆支撑平面上的轨迹圆半径。转向盘转到极限位置时的转弯半径为最小转弯半径。 3、最大总质量(kg):汽…

动态数组的实现

定义 1. 在计算机科学中,数组是由一组元素(值或变量)组成的数据结构,每个元素有至少一个索引或键来标识。 2. 因为数组内的元素是连续存储的,所以数组中元素的地址,可以通过其索引计算出来。 3. 知道了数…

计算机网络-网络层

计算机网络-网络层 以下笔记整理为哔哩哔哩湖科大教书匠的《计算机网络微课堂》的教学视频。 链接:计算机网络微课堂 1. 网络层概述 1.1 网络层的主要任务是实现网络互联,进而实现数据包在各网络之间的传输。 1.2 要实现网络层任务,需要解决…

【飞凌 OK113i-C 全志T113-i开发板】一些有用的常用的命令测试

一些有用的常用的命令测试 一、系统信息查询 可以查询板子的内核信息、CPU处理器信息、环境变量等 二、CPU频率 从上面的系统信息查询到,这是一颗具有两个ARMv7结构A7内核的处理器,主频最高1.2GHz 可以通过命令查看当前支持的频率以及目前所使用主频 …

Spring IoCDI

文章目录 前言什么是Spring1. 什么是 IoC 容器1.1 什么是容器1.2 什么是 IoC 2. 什么是DI IoC & DI 的使用IoC详解Bean的存储Controller注解如何获取Bean1. 根据Bean的名称获取Bean2. 根据Bean类型获取Bean3. 根据Bean名和Bean类型获取Bean Service注解Repository注解Compo…