C++ IO框架

news2024/11/15 16:27:42

文章目录

    • I/O 复用
      • 概述
      • I/O 模型
        • 一个输入操作的两个阶段
    • select 函数
      • 概述
      • 详细解析
        • 函数内容详解
        • `select`总结
    • poll 函数
      • 概述
      • 详细解析
        • 函数内容详解
    • epoll 函数
      • 概述
      • 基础API
      • 注意事项
      • 总结一下select, poll, epoll的区别
    • Reactor 和 Proactor
      • 概述
        • 概念
        • 服务器连接多个客户端的业务场景
        • 解决方案
        • 思考:线程如何高效处理多个连接的业务?
        • 进一步思考
        • I/O 多路复用技术
      • Reactor 模式
        • Reactor 模式概述
        • Reactor 模式的灵活性
        • Reactor 模式的实现方案
        • 总结
      • 单 Reactor 单进程
        • 组件职责
        • 工作流程
        • 优缺点
      • 单 Reactor 多线程 / 多进程
        • 工作流程(多线程为例)
        • 优缺点(多线程)
        • 优缺点(多进程,理论讨论)
      • 总结
      • 多 Reactor 多线程 / 多进程
        • 多 Reactor 多线程
        • 多 Reactor 多进程
        • Proactor 模型

I/O 复用

概述

当TCP客户端同时处理两个输入:标准输入和TCP套接字时,会遇到以下问题:

  • 问题描述:在客户端阻塞于标准输入上的fgets调用时,如果服务器进程突然终止,服务器TCP虽然正确地给客户端发送了一个FIN,但是客户端正阻塞于从标准输入读入的过程,因此无法立即看到这个EOF(文件结束符)。直到从标准输入读到数据后,客户端才能看到EOF,但此时可能已经错过了及时处理服务器关闭的时机。
  • 解决方案需求:这样的进程就需要一种预先告知内核的能力,使得内核一旦发现进程指定的一个或多个I/O条件就绪(如TCP连接关闭、标准输入有数据可读等),就通知进程。这种能力就被称为I/O复用(multiplexing)。

I/O 模型

存在5种主要的I/O模型:

  1. 阻塞式I/O
  2. 非阻塞式I/O
  3. I/O 复用
  4. 信号驱动式I/O
  5. 异步I/O
一个输入操作的两个阶段

一个输入操作通常包括两个不同的阶段:

  • 等待数据准备好:在这个阶段,进程需要等待,直到所需的数据到达内核的缓冲区。
  • 从内核向进程复制数据:一旦数据准备好,内核就会将数据从内核空间复制到用户空间,供进程使用。

这些阶段和模型的不同之处在于它们处理等待数据准备好这一阶段的方式。

select 函数

概述

该函数允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经历一段指定时间后才唤醒它。主旨思想在于不再由应用程序自己监视客户端连接,而是由内核替应用程序监视文件描述符的状态。

详细解析

#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int maxfdpl, fd_set *readset, fd_set *writeset,
			fd_set *exceptset, struct timeval *timeout);

	maxfdpl: 	监控的文件描述符集里最大文件描述符加1,因为此参数会告诉内核检测前多少个文件描述符的状态
	readset: 	监控有读数据到达文件描述符集合,传入传出参数
	writeset: 	监控写数据到达文件描述符集合,传入传出参数
	exceptset: 	监控异常发生达文件描述符集合,如带外数据到达异常,传入传出参数
	timeout: 	定时阻塞监控时间,3种情况
				1.NULL,永远等下去
				2.设置timeval,等待固定时间
				3.设置timeval里时间均为0,检查描述字后立即返回,这称为轮询
	struct timeval {
		long tv_sec; /* seconds */
		long tv_usec; /* microseconds */
	};

    void FD_ZERO(fd_set *set); 			 //把文件描述符集合里所有位清0
    void FD_SET(int fd, fd_set *set); 	 //把文件描述符集合里fd位置1
	void FD_CLR(int fd, fd_set *set); 	 //把文件描述符集合里fd清0
	int  FD_ISSET(int fd, fd_set *set);  //测试文件描述符集合里fd是否置1
函数内容详解
  • 注意事项:

    • select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024。单纯改变进程打开的文件描述符个数并不能改变select监听的文件个数。
  • 描述符就绪条件:

    • 当某个套接字上发生错误时,该套接字将被select标记为既可读又可写。
  • 接收低水位标记和发生低水位标记的目的:

    • 允许应用进程控制select返回可读或可写条件之前有多少数据可读或有多大空间可用于写。例如,可以设置至少存在64字节的数据准备好读时,select才唤醒应用进程,从而避免频繁打断应用进程处理其他工作。
select总结
  • 优点:

    • select遵循POSIX标准,跨平台移植性较好。
    • select监控的超时等待时间可以精细到微秒。
  • 缺点:

    • select所能监控的描述符数量有最大上限,取决于宏_FD_SETSIZE,默认大小为1024。
    • select的监控原理是在内核中进行轮询遍历,这种遍历会随着描述符的增多而性能下降。
    • select返回时会移除所有未就绪的描述符,只给用户返回就绪的描述符集合,但没有直接告诉用户哪个描述符就绪,需要用户自己遍历才能获知。
    • select每次监控都需要重新将集合拷贝到内核中才能进行监控。
    • select每次返回都会移除所有未就绪的描述符,因此每次监控都要重新向集合中添加描述符。

poll 函数

概述

该函数提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息。select函数允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经历一段指定时间后才唤醒它。

详细解析

#include <poll.h>
int poll(struct pollfd *fdarray, unsigned long nfds, int timeout);

	struct pollfd {
		int fd; 		/* 文件描述符 */
		short events; 	/* 监控的事件 */
		short revents;  /* 监控事件中满足条件返回的事件 */
	};

	events标志以及测试revents标志的一些常量:
	—————————————处理输入—————————————————————
	POLLIN			普通或带外优先数据可读,即POLLRDNORM | POLLRDBAND
	POLLRDNORM		数据可读
	POLLRDBAND		优先级带数据可读
	POLLPRI 		高优先级可读数据
	—————————————处理输出—————————————————————
	POLLOUT			普通或带外数据可写
	POLLWRNORM		数据可写
	POLLWRBAND		优先级带数据可写
	—————————————处理错误————————————————————
	POLLERR 		发生错误
	POLLHUP 		发生挂起
	POLLNVAL 		描述字不是一个打开的文件

	nfds 			监控数组中有多少文件描述符需要被监控

	timeout 		毫秒级等待
		-1:阻塞等,#define INFTIM -1 				Linux中没有定义此宏
		0:立即返回,不阻塞进程
		>0:等待指定毫秒数,如当前系统时间精度不够毫秒,向上取值



函数内容详解
  • 注意事项:
    • 如果不再监控某个文件描述符时,可以把pollfd结构体中的fd成员设置为-1,这样poll将不再监控此pollfd,下次poll返回时,会把对应的revents成员设置为0。
    • pollfd结构包含了要监视的事件(通过events成员)和发生的事件(通过revents成员),不再使用select的"值-结果"传递方式。
    • 同时,poll函数对pollfd数组的大小并没有最大数量限制(但监控的文件描述符数量过大后,性能也会有所下降)。
    • select函数一样,poll返回后,需要轮询pollfd数组来获取就绪的描述符。

epoll 函数

概述

epoll是Linux下多路复用I/O接口(select/poll)的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。因为它会复用文件描述符集合来传递结果,而不用迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合。获取事件时,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合即可。目前,epoll是Linux大规模并发网络程序中的热门首选模型。epoll除了提供select/poll那种IO事件的电平触发(Level Triggered)外,还提供了边沿触发(Edge Triggered),这使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

基础API

  • 创建一个epoll句柄,参数size用来告诉内核监听的文件描述符的个数,与内存大小有关。
#include <sys/epoll.h>
int epoll_create(int size)		size: 监听数目

  • 控制某个epoll监控的文件描述符上的事件:注册、修改、删除。
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
		epfd: epoll_creat的句柄
		op: 表示动作,用3个宏来表示: 
			EPOLL_CTL_ADD (注册新的fd到epfd),
			EPOLL_CTL_MOD (修改已经注册的fd的监听事件),
			EPOLL_CTL_DEL (从epfd删除一个fd);
		event: 	告诉内核需要监听的事件

		struct epoll_event {
			__uint32_t events; /* Epoll events */
			epoll_data_t data; /* User data variable */
		};
		typedef union epoll_data {
			void *ptr;
			int fd;
			uint32_t u32;
			uint64_t u64;
		} epoll_data_t;

		EPOLLIN : 	表示对应的文件描述符可以读(包括对端SOCKET正常关闭)
		EPOLLPRI: 	表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来)
		EPOLLOUT: 	表示对应的文件描述符可以写
		EPOLLERR: 	表示对应的文件描述符发生错误
		EPOLLHUP: 	表示对应的文件描述符被挂断;
		EPOLLET:  	将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)而言的
		EPOLLONESHOT: 只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里


  • 等待所监控文件描述符上有事件的产生,类似于select()调用。
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
	events: 	用来存内核得到事件的集合,
	maxevents: 	告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size,
	timeout: 	是超时时间
				-1: 	阻塞
				0: 	立即返回,非阻塞
				>0: 	指定毫秒
	返回值: 	成功返回有多少文件描述符就绪,时间到时返回0,出错返回-1


注意事项

epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

  • 水平触发(LT): 默认工作模式,即当epoll_wait检测到某描述符事件就绪并通知应用程序时,应用程序可以不立即处理该事件;下次调用epoll_wait时,会再次通知此事件。
  • 边缘触发(ET): 当epoll_wait检测到某描述符事件就绪并通知应用程序时,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次通知此事件(直到你做了某些操作导致该描述符变成未就绪状态了,也就是说边缘触发只在状态由未就绪变为就绪时只通知一次)。

ET和LT原本应该是用于脉冲信号的,可能用它来解释更加形象。Level和Edge指的就是触发点,Level为只要处于水平,那么就一直触发,而Edge则为上升沿和下降沿的时候触发。比如: 0->1 就是Edge,1->1 就是Level。ET模式很大程度上减少了epoll事件的触发次数,因此效率比LT模式下高。

总结一下select, poll, epoll的区别

(此处应详细列出三者的主要区别,但原文未具体给出,以下为一般性总结)

  • select

    • 监视的文件描述符数量有限制(通常为1024)。
    • 监视文件描述符时,需要将它们从用户空间拷贝到内核空间。
    • 每次调用select时,都需要重新设置文件描述符集合。
    • 只提供了水平触发。
  • poll

    • 监视的文件描述符数量没有硬性限制,但受限于系统资源。
    • 与select类似,每次调用都需要重新设置文件描述符集合。
    • 同样只提供了水平触发。
  • epoll

    • 没有监视文件描述符数量的限制(实际上受限于系统资源)。
    • 只需在开始时设置一次文件描述符集合,之后可以复用。
    • 提供了水平触发和边缘触发两种模式。
    • 只在有事件发生时才通知,减少了CPU的使用率。

Reactor 和 Proactor

概述

概念
  • PPC (Process per Connection): 每次有新的连接就新建一个进程去专门处理这个连接的请求。
  • TPC (Thread per Connection): 每次有新的连接就新建一个线程去专门处理这个连接的请求,比PPC更轻量。
服务器连接多个客户端的业务场景
  • 直接方式: 为每一条连接创建线程(或进程,但线程更常用因其轻量级)。
  • 问题: 频繁创建和销毁线程带来性能开销和资源浪费,尤其在高并发场景下(如几万条连接)不现实。
解决方案
  • 资源复用: 创建线程池,将连接分配给线程池中的线程处理,一个线程处理多个连接的业务。
思考:线程如何高效处理多个连接的业务?
  • 阻塞问题: 当一个线程处理多个连接时,若某个连接在read操作时无数据可读,线程将阻塞,无法处理其他连接。
  • 非阻塞轮询: 将socket改为非阻塞,线程不断轮询调用read,但此方法消耗CPU且效率随连接数增加而降低。
进一步思考
  • 问题: 线程如何仅在连接上有数据时发起读请求?
  • 解决方案: I/O 多路复用技术
I/O 多路复用技术
  • 定义: 用一个系统调用函数监听所有关心的连接,一个线程可监控多个连接。
  • 实现: select/poll/epoll 是内核提供给用户态的多路复用系统调用。
  • 工作原理:
    • 注册连接: 将关心的连接传给内核。
    • 内核检测: 内核检测这些连接上的事件。
    • 阻塞与返回:
      • 无事件: 线程阻塞在系统调用上,不消耗CPU轮询。
      • 有事件: 内核返回产生事件的连接,线程处理这些连接的业务。

Reactor 模式

Reactor 模式概述

Reactor 模式(也称Dispatcher模式)主要由Reactor和处理资源池这两个核心部分组成,作用如下:

  • Reactor:负责监听和分发事件,事件类型包含连接事件、读写事件。
  • 处理资源池:负责处理事件,如 read -> 业务逻辑 -> send
Reactor 模式的灵活性

Reactor 模式是灵活多变的,可以应对不同的业务场景,其灵活性体现在:

  • Reactor 的数量:可以只有一个,也可以有多个。
  • 处理资源池:可以是单个进程/线程,也可以是多个进程/线程。
Reactor 模式的实现方案

将上述两个因素进行排列组合,理论上可以有以下四种方案选择:

  1. 单 Reactor 单进程 / 线程

    • 优点:实现简单,不需要考虑进程间通信和多进程竞争。
    • 缺点:无法充分利用多核CPU性能,业务处理耗时较长时会造成响应延迟。
    • 应用场景:适用于业务处理非常快速的场景。
  2. 单 Reactor 多进程 / 线程

    • 优点:能够充分利用多核CPU的能力。
    • 缺点:引入多线程/进程,带来多线程/进程竞争资源的问题,需要处理并发问题。
    • 实际应用:多线程方式较为常见,多进程方式实现复杂且少见。
  3. 多 Reactor 单进程 / 线程

    • 说明:此方案相比单 Reactor 方案复杂且没有性能优势,实际中并未应用。
  4. 多 Reactor 多进程 / 线程

    • 优点:主线程和子线程分工明确,主线程只负责接收新连接,子线程负责完成后续的业务处理,交互简单。
    • 实际应用:Netty 和 Memcache 等开源软件采用了此方案。
总结

Reactor 模式通过灵活配置Reactor的数量和处理资源池的类型,可以适应不同的业务场景需求。其中,多 Reactor 多线程方案因其高效性和易实现性,在实际项目中得到了广泛应用。

单 Reactor 单进程

在单 Reactor 单进程的模型中,所有组件(Reactor、Acceptor、Handler)都运行在同一个进程中。这种模型简单直观,但有其特定的优缺点。

组件职责
  • Reactor:负责监听和分发事件,使用selectpollepoll等系统调用来等待事件的发生。
  • Acceptor:负责处理连接建立的事件,通过accept系统调用获取新的连接,并为每个连接创建一个Handler对象。
  • Handler:负责处理非连接建立事件(如读写事件),通过read读取数据,执行业务逻辑,然后通过send发送响应。
工作流程
  1. Reactor通过系统调用监听事件。
  2. 当事件发生时,Reactor通过dispatch方法分发事件。
  3. 如果是连接建立事件,则交给Acceptor处理,Acceptor通过accept获取连接并创建Handler。
  4. 非连接建立事件则直接交给对应的Handler处理。
  5. Handler执行read -> 业务处理 -> send流程。
优缺点
  • 优点
    • 实现简单,无需处理进程间通信。
    • 无需考虑多进程竞争资源的问题。
  • 缺点
    • 无法充分利用多核CPU的性能。
    • Handler处理业务时阻塞整个进程,可能导致响应延迟。
  • 应用场景:适用于业务处理非常快速的场景,不适合计算密集型任务。

单 Reactor 多线程 / 多进程

单 Reactor 多线程/多进程模型在单 Reactor 单进程的基础上进行了扩展,以更好地利用系统资源。

工作流程(多线程为例)
  1. Reactor通过系统调用监听事件。
  2. 当事件发生时,Reactor通过dispatch方法分发事件。
  3. 连接建立事件交给Acceptor处理,Acceptor通过accept获取连接并创建Handler。
  4. 非连接建立事件则交给对应的Handler处理。但此时Handler只负责数据的接收和发送。
  5. Handler通过read读取到数据后,将数据传递给子线程中的Processor对象进行业务处理。
  6. Processor处理完业务后,将结果返回给主线程中的Handler。
  7. Handler通过send方法将响应结果发送给客户端。
优缺点(多线程)
  • 优点
    • 能够充分利用多核CPU的能力,提高系统吞吐量。
  • 缺点
    • 引入多线程竞争资源的问题,需要处理并发访问共享资源的情况,如使用互斥锁。
    • 线程间通信和同步可能增加系统复杂度。
优缺点(多进程,理论讨论)

虽然实际中很少使用单 Reactor 多进程模型,但理论上其优缺点与多线程类似,但进程间通信(如通过管道、消息队列、共享内存等)通常比线程间通信更复杂且开销更大。

总结

单 Reactor 多线程模型在实际应用中更为常见,因为它能够较好地平衡系统资源的利用和实现的复杂度。然而,在面对极高并发的场景时,单 Reactor 模型可能会成为性能瓶颈。此时,可以考虑使用多 Reactor 模型,即多个Reactor分别监听和处理不同的事件,以进一步提高系统的并发处理能力。

多 Reactor 多线程 / 多进程

多 Reactor 多线程

在多 Reactor 多线程模型中,系统被划分为多个部分,每个部分都负责不同的任务,以提高系统的并发处理能力和响应速度。

  • MainReactor:在主线程中运行,负责监听和接收新的连接事件。当有新连接到达时,MainReactor通过accept方法接收连接,并将新连接分配给某个子线程中的SubReactor。
  • SubReactor:在子线程中运行,负责监听由MainReactor分配的连接上的读写事件。当有新的事件(如可读、可写)发生时,SubReactor调用对应的Handler来处理。
  • Handler:用于处理具体的业务逻辑,包括读取数据、处理业务和发送响应。

优点

  • 主线程和子线程分工明确,提高了系统的并发处理能力。
  • 主线程和子线程之间的交互简单,减少了锁的使用和上下文切换的开销。
  • 子线程可以直接将处理结果发送给客户端,无需返回给主线程。

实现复杂度
虽然多 Reactor 多线程模型在概念上比单 Reactor 多线程更复杂,但由于其清晰的分工和简单的交互,实际实现起来反而更加简单和高效。

多 Reactor 多进程

多 Reactor 多进程模型与多线程模型类似,但主要区别在于使用进程而非线程来隔离不同的任务。然而,正如之前提到的,由于进程间通信(IPC)的复杂性和开销,这种模型在实际应用中较少见。

Nginx 采用了类似但有所差异的多进程模型,其中主进程用于初始化和管理子进程,但并不直接处理连接。连接由子进程中的Reactor来accept和处理。

Proactor 模型

Proactor 模型是一种异步I/O模型,它允许操作系统内核来处理I/O操作,并在操作完成后通知用户进程。这与Reactor模型的同步I/O操作形成对比。

  • Proactor Initiator:负责创建Proactor和Handler,并将它们注册到内核的Asynchronous Operation Processor中。
  • Asynchronous Operation Processor:内核组件,负责处理注册请求,执行I/O操作,并在操作完成后通知Proactor。
  • Proactor:根据Asynchronous Operation Processor的通知,调用相应的Handler来处理业务逻辑。
  • Handler:处理具体的业务逻辑,也可以注册新的Handler。

优点

  • 异步I/O能够充分利用DMA(直接内存访问)特性,使得I/O操作与CPU计算可以重叠进行,从而提高系统性能。

实现难度

  • 真正的异步I/O在操作系统层面实现复杂,目前只有少数系统(如Windows的IOCP)提供了完善的支持。
  • 在Linux下,虽然有AIO(异步I/O)机制,但其性能和成熟度都不如Windows的IOCP。因此,许多在Linux下的网络库(如Boost.Asio)采用Reactor模式模拟异步I/O。

总的来说,选择哪种模型取决于具体的应用场景、性能要求和操作系统的支持情况。在实际开发中,需要根据这些因素综合考虑,选择最适合的模型。

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

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

相关文章

【DVWA】——File Upload(文件上传)

&#x1f4d6; 前言&#xff1a;文件上传漏洞是由于对上传文件未作过滤或过滤机制不严&#xff08;文件后缀或类型&#xff09;&#xff0c;导致恶意用户可以上传脚本文件&#xff0c;通过上传文件可达到控制网站权限的目的。 目录 &#x1f552; 1. Low&#x1f552; 2. Mediu…

Window10安装多智能体强化学习平台(SMAC)

基本步骤可以参照博客&#xff1a;window10安装多智能体强化学习平台&#xff08;SMAC&#xff09;_conda如何安装smac库-CSDN博客 注意1&#xff1a;上面所涉及的python第三方库版本不一定要安装博客指定版本。 注意2&#xff1a;星际争霸需要安装国际服(国服不支持)&#x…

Redisson实现分布式锁(看门狗机制)

目录 可重入锁&#xff1a; 锁重试和看门狗机制&#xff1a; 主从一致性&#xff1a; 首先引入依赖&#xff0c;配置好信息 3.使用Redisson的分布式锁 可重入锁&#xff1a; 可重入锁实现是通过redsi中的hash实现的&#xff0c;key依旧是业务名称加id&#xff0c;然后第一个…

正式发售!《黑神话:悟空》背后的技术力量——UE5与实时云渲染

千呼万唤始出来&#xff0c;《黑神话&#xff1a;悟空》终于在今年8月发售了&#xff0c;相信大家都已经玩起来了&#xff01; 作为国产游戏的画质巅峰之作&#xff0c;《黑神话&#xff1a;悟空》凭借其令人叹为观止的画面质量和游戏体验&#xff0c;赢得了广泛的好评。这一切…

实时监控分析广告数据跳转统计平台源码

广告跳转实时分析页面统计系统&#xff0c;可选择生成html页面样式&#xff0c;可自定义设置页面域名后缀&#xff0c;可指定跳转指定网址&#xff0c; 可记录单个页面的访问记录&#xff0c;可对生成的单个链接进行备注&#xff0c;自定义等待时间进行跳转。 源码下载&#…

内网渗透- 内网渗透的基本知识

攻击流程讲解 内网介绍 内网也指局域网&#xff0c;是指在某一区域内由多台计算机互联而成的计算机组&#xff0c;组网范围通常在数千米以内。在局域网中&#xff0c;可以实现文件管理、应用软件共享、打印机共享、工作组内的日程安排、电子邮件和传真通信服务等。内网是封闭的…

Python 课程11-Web 开发

前言 Web 开发已经成为现代软件开发的核心领域之一&#xff0c;许多应用程序和服务都通过 Web 来与用户和其他系统交互。Python 作为一门广泛使用的编程语言&#xff0c;提供了多种 Web 开发框架&#xff0c;其中最流行的两个框架是 Flask 和 Django。 Flask 是一个轻量级的 W…

Dubbo SPI源码

文章目录 Dubbo SPI使用方式AOP功能源码剖析SPI注解1.获取加载器2.获取拓展实例对象3.创建拓展类的实例对象 Dubbo SPI Dubbo 的 SPI&#xff08;Service Provider Interface&#xff09;机制是一种强大的扩展机制&#xff0c;它允许开发者在运行时动态地替换或增加框架的功能。…

2-95 基于matlab的模板定位

基于matlab的模板定位。利用①相关匹配&#xff08;Correlation Matching&#xff09;、②基于Hausdorff距离匹配方法 及③考虑对场景图象距离变换&#xff08;Distance Transform&#xff09;的Hausdorff距离匹配方法,实现模板目标在场景图象中的定位。程序已调通&#xff0c;…

XShell快速连接虚拟机(Ubuntu系统)

目录 前言 一 (XShell)(虚拟机 )(Ubuntu)下载 二 虚拟机的ip查找 三 虚拟机中安装连接环境 四 开启ssh-server服务 五 验证是Ubuntu是否开启ssh-server服务 六 连接XShell软件 前言 对于刚开始探索 Linux 世界的新手来说&#xff0c;拥有一台自己的服务器可能并不现实。幸运的…

linux服务器配置及服务器资源命令使用查看

在做i性能压测之前&#xff0c;所了解的服务器配置&#xff1a;CPU、内存、硬盘、网络 一、查看cpu信息 常用命令&#xff1a;cat /proc/cpuinfo或者lscpu、pidstat等 需要关注的&#xff1a; Architecture: x86_64 # 架构信息&#xff0c;表示系统的CPU架构为x86_64&#…

业务资源管理模式语言14

第三节&#xff1a;在前面讨论的Resource Transcations&#xff08;资源事务&#xff09;中有许多共同的行为。其中一个行为可以包含多个项目&#xff0c;每个项目对应一个不同的资源&#xff08;ItemizeTheResourceTransaction&#xff08;11&#xff09;。事务可以产生一些报…

GitLab权限及设置

之前很少关注这些&#xff0c;项目的权限&#xff0c;一般由专门的管理人员设置。 但自己创建的项目自己可以设置权限。下面是一些笔记。 GitLab中用户权限_gitlab 权限-CSDN博客 开发中遇到要将自己这块的代码上传到Git&#xff0c;由其他组的同事拉取后继续开发。上传代码后…

【JVM】概述

前言 Java的技术体系主要由支撑Java程序运行的虚拟机、提供各开发领域接口支持的Java类库、Java编程语言及许许多多的第三方Java框架&#xff08;如Spring、MyBatis等&#xff09;构成。在国内&#xff0c;有关Java类库API、Java语言语法及第三方框架的技术资料和书籍非常丰富&…

Oracle从入门到放弃

Oracle从入门到放弃 左连接和右连接Where子查询单行子查询多行子查询 from子句的子查询select子句的子查询oracle分页序列序列的应用 索引PL/SQL变量声明与赋值select into 赋值变量属性类型 异常循环游标存储函数存储过程不带传出参数的存储过程带传出参数的存储过程 左连接和…

【爬虫软件】批量采集抖音主页已发布作品

一、背景介绍 以下xx代表你猜中的部分。 1.1 爬取目标 用python开发的xx爬虫采集软件&#xff0c;可自动按博主抓取其已发布视频。 为什么有了源码还开发界面软件呢&#xff1f;方便不懂编程代码的小白用户使用&#xff0c;无需安装python&#xff0c;无需改代码&#xff0c;…

瞳孔检测系统源码分享

瞳孔检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

CS61C 2020计算机组成原理Lecture01-数字表示,溢出

1. 原码 原码就是符号化的数值&#xff0c;其编码规则简单直观&#xff1a;正数符号位用0表示&#xff0c;负数符号位用1表示&#xff0c;数值位保持不变。 x0.1101&#xff0c;则[x]原0.1101&#xff1b;x1101&#xff0c;则[x]原01101x -0.1111&#xff0c;则[x]原1.1111&…

《Mesh 组网和 AC+AP 组网的优缺点》

Mesh 组网和 ACAP 组网的优缺点。 Mesh 组网的优点&#xff1a; 1. 部署灵活&#xff1a;节点之间可以通过无线方式连接&#xff0c;新增节点比较方便&#xff0c;无需事先规划布线。 2. 自我修复和优化&#xff1a;如果某个节点出现故障&#xff0c;网络可以自动重新路由数据&…

MyBatis 数据处理:主键获取、批量删除与动态表名

目录 MyBatis 数据处理&#xff1a;主键获取、批量删除与动态表名 1.主键获取 1&#xff09;mapper接口 2&#xff09;mapper.xml 3&#xff09;测试代码 4&#xff09;测试结果 2.批量删除 1&#xff09;mapper接口 1-使用手动拼接字符串数组的方法 2-使用mybatis中的foreach标…