Linux:理解信号量以及内核中的三种通信方式

文章目录

  • 共享内存的通信速度
  • 消息队列
    • msgget
    • msgsnd
    • msgrcv
    • msgctl
  • 信号量
    • semget
    • semctl
  • 内核看待ipc资源
    • 单独设计的模块
    • ipc资源的维护
  • 理解信号量
  • 总结

本篇主要是基于共享内存,延伸出对于消息队列和信号量,再从内核的角度去看这三个模块实现进程间通信

共享内存的通信速度

共享内存是所有进程间通信里面速度最快的,并且是没有质疑的,何以见得这个结论呢?

要说这个结论,还要从管道说起,对于进程来说,如果想要使用管道进行通信,那么首先要有进程的PCB和对应的进程地址空间,其次如果选择管道进行通信,那么就会建立管道之后,将用户自己的数据交给另外一个进程,通过write的系统调用写到缓冲区中,本质上就是把用户级的缓冲区直接经过系统调用拷贝到内核的管道中,对于读端来说,就是用read系统调用再读取信息,相当于是把内核中的数据经过read系统调用,把数据拷贝到用户空间内,此时就完成了从进程a到进程b数据通信的目的

而对于共享内存来说,创建好共享内存之后,经过挂接在自己的地址空间的共享区中就能找到这个区域,之后就可以在这个共享内存中进行写入,写入后共享内存这里就会立刻有这段信息,在这个过程中是没有任何系统调用的,写的信息立刻就能看到,没有任何延误,换而言之,这两个进程之间不需要通过内核进行拷贝,甚至都不需要用户定义的缓冲区,直接向共享内存中写入信息,用户立刻就能看到,可以理解为是把用户级别的缓冲区合并成一个缓冲区,只要进程a向里面写,进程b立刻就能看到,有效的减少了数据通信过程中经由数据拷贝造成的消耗问题

因此我们说,对于共享内存来说,它的效率体现在可以减少数据拷贝,不需要经过用户到内核,内核到用户这样的拷贝,而是直接在用户的层面上,进程a向共享内存写信息,进程b就能看到,甚至可能都不需要缓冲区的概念,所以是高效的

那能减少多少次拷贝呢?

对于这个问题来说,这里简单做个解释,具体可能会因为实际场景和配置略有差距

假设现在有输入的函数需求,数据也从键盘输入了,那么从文件的角度来讲,就相当于从文件里面读取了信息,而从文件中读取信息也算是一层拷贝,而现在有输出的需求,需要把数据输出到显示器上,而现在的数据是存储到内存或者是缓冲区中,而从内存刷新到外设这个过程,也算是一层拷贝,而实际上,CPU只认识内存,所以想要让CPU处理数据,就必须把外设的信息加载到内存中,再从内存处理后刷新到外设上,而这个过程实际上就是把数据从一个设备拷贝到另外一个设备上,凡是数据迁移,都可以看成是拷贝,所以对于管道文件来说,不管是write系统调用还是read系统调用,都是和内核进行交互,从内核交互的角度来讲,这两个函数其实就是一个拷贝的函数,那么来回进行数据的拷贝,效率自然不能和共享内存比

那么回到这个问题,到底可以减少多少次拷贝?假设现在有硬件,那么从键盘到显示器这个过程,输入数据是需要用户自己提供缓冲区,把数据从键盘读取到缓冲区中,再把数据从缓冲区拷贝到管道当中,而最终目标是要打印到显示器上,那显示器也是有对应的缓冲区的,所以就把数据再拷贝到缓冲区中,最终就能写到显示器中,这么一套理论,保守的来讲都有四次的拷贝过程,如果把语言本身提供的缓冲区也加上,只会比这个过程更多

在这里插入图片描述

那如果对于共享内存来说呢?从键盘中读取的数据,直接写到共享内存中,读取的进程只需要把共享内存中的数据显示到显示器上就可以了,此时就相当于第一次拷贝,将数据从外设写到共享内存中,第二次把共享内存中的数据写到显示器上,两次拷贝就刷新过去了,直接就省去了内核之间的拷贝过程,就算不考虑语言级别的缓冲区,也能减少两次拷贝

在这里插入图片描述

消息队列

消息队列提供一个进程给另外一个进程发送数据块的能力,那如何理解这句话呢?先画出下面的示意图

在这里插入图片描述
这是对于消息队列画出的最基本的示意图,在ipc资源当初被设计的时候,能够在内核层面上创建共享内存,创建对应的结构来管理这样的共享内存,那在操作系统层面上也可以创建一个队列,这个队列的名字就叫做msg_queue,这个队列刚开始是空的,但是用户是有数据的,通过一定的接口传递到队列中,此时就会在队列的底层形成一个一个的节点,这里可以理解成是链队列,把这个链队列链入到这个队列之中

消息队列的本质是要进行进程间通信,而只要涉及到进程间通信就离不开的话题是让两个不同的进程看到同一份资源,这也是在先前已经建立起来的思想观念,那么基于这个原因,进程a发送的消息队列中的内容必然是需要让进程b见到的,所以就有了接口:

msgget

在这里插入图片描述
它其实和共享内存是很相似的,也是从系统V中获取一个消息队列的标识符,只要调用了这个接口,那么就可以在内核中创建出一个消息队列,这个消息队列就可以使用了

那随之而来的下一个问题是,现在进程a创建出对应的消息队列,也满足了让不同的进程看到同一份资源这样的一个基本的条件,但是现在面临的问题是,如果进程a向消息队列中写信息,进程b也向消息队列中写信息,那么如何去进行区分呢?消息队列中的节点对于不同的进程来说想要看到的信息当然是不一样的,所以必然有对应的标识符,由进程a创建的数据节点中就会带有进程a的标识符,由进程b创建的节点就会有进程b的标识符,这样不同的进程在识别到某个资源中没有自己所对应的标识符就不会识别了,而是只会识别到自己对应的标识符

消息队列由于和共享内存一样,都是隶属于系统V内部的结构,所以它们之间必定会遵循一定的标准,所以从接口或是其他的层面上都几乎相似,因此消息队列的生命周期也是随内核的,而操作系统中各种各样的进程也都会有通信的需求,如果创建出各种各样的消息队列,那么操作系统也必然会为这一个一个的消息队列进行维护,所以从逻辑上讲,消息队列和共享内存基本上是一样的,所以对于消息队列的管理,就转换成了对于描述该消息队列的数据结构对象的增删查改,这样就把消息队列管理起来了

msgsnd

在这里插入图片描述
发送数据块到消息队列

msgrcv

在这里插入图片描述
获取消息队列中的数据块

msgctl

在这里插入图片描述
这个接口也和共享内存基本一致,这里不再过多描述

信号量

信号量本质上就是一种计数器,用来保护共享资源,未来可能会有多个线程看到同一个公共资源,那在执行和访问共享资源的过程中,就可能会产生问题,例如一个进程正在写信息,另外一个进程就已经来读了,那么就会产生数据干扰,这当然是不被操作系统认可的行为,为了避免这样的问题导致内部数据紊乱,所以就引入了信号量的概念,来保护操作系统内部的公共资源,这是对于信号量最初步的理解

semget

在这里插入图片描述
这是信号量的创建接口

semctl

在这里插入图片描述
这是信号量的控制接口,和消息队列以及共享内存不太一样的是,多了一个可变参数,所以对于信号量的控制相比起其他来说要略复杂一些

消息队列和共享内存都有具体管理的数据结构对象,所以对于信号量也不例外,肯定有其对应的管理对象,所以也会有对应的struct ipcperm结构体对象

对于信号量之后的其余内容,放在之后的内容里,这个模块本身主要是要对于共享内存的理解,但由于消息队列和信号量都是ipc资源,所以拿来一谈,之后对于信号量还有更多的内容补充

内核看待ipc资源

下面进行的模块是,内核是如何对待ipc资源的

上述有了三种共享资源,有共享内存,消息队列,信号量,由于这三个模块都是遵循一套标准做出来的,所以也是比较相似,例如接口的设计,数据结构的管理方式,以及返回的id值,那对于操作系统来说,是不是应该把这些也进行统一的管理呢?答案是肯定的

单独设计的模块

第一个想要输出的结论是,这个模块是操作系统内部单独设计出的模块,对于模块的概念,大体上可以细分为进程管理,内存管理,文件管理,驱动管理,这是操作系统的四大管理模块,而对于ipc资源的管理也是一个模块,只不过是下属的细分模块,不属于最大的四个管理模块,有了这个概念之后,那么在操作系统内部是如何进行管理的呢?

ipc资源的维护

ipc资源是如何在内核中进行维护的呢?现在有三种共享资源,这三种共享资源又有它们对应的id,key值,这些分散的数据理应被管理起来,事实上操作系统也确实把他们管理起来了

在这里插入图片描述
那在内核中是如何进行数据维护的呢?在操作系统内部存在这样的结构

struct ipc_id_ary
{
	int size;
	struct kern_ipc_perm *p[0];
}

这个结构体中存储的是数组元素个数以及一个柔性数组,在上图中也有对应,这里单独将其拿出分析

那生成这样的一个结构,存放的数据类型是kern_ipc_perm的一个结构体类型的指针,这个指针会指向一个指针数组,这个指针数组中存储的不是其他信息,存储的是具体的ipc资源的结构体的开头的第一个元素,这也就是为什么在内核中不管是消息队列还是共享内存还是信号量,它们的第一个元素都是一个perm类型的字样,就是为了方便于将这个内容统一管理到这样的一个结构体中,这样就能把所有的ipc资源统一用指针数组来管理起来

那这有什么用?用处就是未来可以通过这个内容找到对应的内容,在实际的使用中,可以通过数组中的一个指针,找到它对应的属于哪个共享资源,然后转换成对应的类型,有了起始地址和偏移量,整个数组内的对应元素的各种内容也就都有了,这样就能做到进行数据的访问过程

因此有了这样的结构,之后再管理所有的ipc资源的时候,在设计模式中就将所有内核结构的第一个成员设计成一样的,都是key值,未来在辨别这些ipc资源是否存在的时候,只需要遍历这个数组指针,在这个数组中找到各个内容中的key值,然后判断这个key值是否存在就可以了,如果不存在就进行创建,因此往后就可以统一用数组的方式访问对应的资源,如果想要找到对应资源中的其他信息也可以做出指针对类型做强转来定位到具体的位置

整个流程其实有些类似于C++中的多态,多态的概念已经不是第一次提出了,再对于外设作为文件系统的篇章中,已经讲述了虚拟文件系统就有些类似于多态,而在这里也是第二次提出对于多态的概念,多态就是令子类去继承基类,那么对应到ipc的模式中,每一个具体的ipc资源填充不同的属性,但是开头的元素都一样,再定义一个指针数组,指针数组都会指向一个具体的ipc资源,这就是一个典型的多态的过程

在Linux内核当中,管理System V版本的ipc资源,虽然内部实现的差异比较大,但是利用抽象的方式还是用c语言实现了多态,最终把所有的ipc资源都收拢在了一个数组中,这样对于ipc资源的管理就转换成了对于这个数组的增删查改,这样就做到了管理好共享资源

理解信号量

前面对于信号量的初步认知是,信号量是一个计数器,这里开始要对于信号量有一个更加具体的认知

首先,对于信号量的引入是,要让不同的进程看到同一份资源,这也是进程通信的本质,所以信号量的引入本质上是要让多个执行流看到同一份资源,这部分资源就被叫做公共资源,无论是命名管道还是匿名管道,本质上都是一份公共的缓冲区资源,而这些共享资源都是操作系统提供的,这也是前面已经拥有的概念,如果这个公共资源是由某个特定进程提供的,那么就会违背进程的独立性,所以在这样的情况下,又会诞生的新的问题是,当有很多的进程同时挂接到这块公共资源后,去进行多进程并发访问这块资源的时候,很可能会出现覆盖的情况,导致出数据不一致这样的问题出现,那么基于这个问题的解决方案是,必须要把这部分内容保护起来,把这部分内容保护起来就需要引入的两个概念叫做互斥和同步

互斥和同步是解决数据不一致的两种解决方式,那具体是如何解决的?结论是用户自己来解决,或者是操作系统来帮用户解决,对于匿名管道,命名管道,消息队列这样的通信方式,其实就是操作系统来帮助用户来解决的,因为管道是自带同步机制,消息队列也是由操作系统帮助用户进行维护,唯独是这块共享内存,操作系统从本质上来说没有做任何事,它只是帮助用户从内存中拿到了这块区域,开辟出来了这块区域,但是内核没有对于共享内存做出任何的保护,因为共享内存是通信速度中最快的,所以操作系统没有对于共享内存做出保护,那么对于共享内存来说该如何进行数据的保护工作?那么就因此有了下面的话题

在谈下面的话题前,先对于几个有一个基本的认知:

互斥和同步

互斥:任何一个时刻只允许一个执行流访问公共资源,加锁完成
同步:多个执行流执行的时候,按照一定的顺序执行

临界资源和临界区

对于要被保护起来的公共资源,这部分资源就叫做临界资源,比如对于操作系统来说,它会把管道保护起来,因为管道就是一种临界资源

而访问临界资源的这些代码和操作,就被叫做是临界区,由此就引出了临界资源和临界区的概念,与之对应的还有非临界资源和非临界区两个概念,比如对于访问键盘,显示器,或是定义变量这样的行为,就属于是非临界区的操作,但更重要的概念是,临界资源的访问是要通过代码访问的,也就是说是通过临界区去访问的,所以用户要对临界资源进行保护,其实只需要保护好临界区就可以,换句话说就是把代码保护好,写好代码,这样就保护好了临界资源,于是就有了加锁的概念,对于这个概念不是这里的重点,在之后再进行学习

原子性

原子性的概念虽然是一个新的词语,但是却并不是第一次提及,所谓原子性,就是说操作一件事没有中间状态,要不然把这件事都做完,要不然压根不做,对于这件事只有两个状态,完成或是未完成,这样的性质就叫原子性

信号量

有了上述的概念,就引出了信息量的概念

在操作系统内部有很多的公共资源,这里假设有一个具体的值,假设现在有一份公共资源,其中可以允许有100个进程同时进行访问,那么此时就有一个计数器来了,计数器就负责保护这块公共资源,它只允许最多有100个进程来访问这块资源,每当有一个进程对于这块公共资源进行占用,计数器的值就减去1,当这个进程离开这块公共资源,这个计数器就加上1,表示可以访问的进程又多了一个,所以说,对于这种用来衡量公共资源的数目,最终达到对公共资源分配的这样一个目的,这种计数器就叫做信号量,所以信号量的本质就是一个计数器,这是在最初就引出的概念,信号量的操作规则就是对于某一个执行流,向要访问公共资源中的某一个资源,不是直接去访问,而是要让执行流去申请信号量资源,这样信号量资源的计数器就能做出对应的改变,只要申请成功了就能去访问,这种就叫做预定机制,对于信号量的大体框架就搭建完毕了,这也就是信号量最初始的理解

但是这远远不够,对于信号量还有很多地方没有解释清楚,下面选出一部分来进行解析

  1. 信号量的本质是一种计数器,执行流就是进程,当有进程要访问公共资源中的某一个资源的时候,要先申请信号量,只要把信号量申请成功,就已经完成了对应的预定功能,在合适的时候就可以进入来访问了,在申请不成功的时候怎么办呢?对应的执行流就要进行阻塞,正式因为有了信号量的概念,从此之后这部分公共资源就能被保护起来了,而不是被多个进程随意的读取数据,导致数据残缺的问题出现,换而言之,操作系统中由于有信号量的存在,所以整个公共资源的访问上限被决定好了,也就意味着访问的上限是可控的,信号量的本质是用来描述公共资源中资源的数量,申请信号量的本质是对公共资源的一种预定机制,当进程申请信号量的时候,申请成功就可以访问,申请失败就要被阻塞挂起,直到申请成功后,就能继续访问这块内容
  2. 如果这个计数器的最大值为1呢?也就是说,同一时刻只允许有一个进程来对这块区域进行访问,多余的内容都不允许访问,那么本质上就实现了一个互斥的功能,同一时刻只允许一个执行流访问公共资源,也就是一种加锁,这样就实现了一个互斥锁,这样的内容就被叫做是二元信号量,用信号量的方式实现了加锁和解锁的过程,完成了互斥的效果,所以未来,在操作系统的内部有一份公共的资源,所有的进程都能看到这块资源,但是如果想要使用这块资源,就假设现在这块资源可以被拆成很多小资源,例如现在有一块共享内存有16kb,现在把这块内存拆成16个小块,一个小块是1kb,这样就能做到允许16个进程同时进来,访问的是不同的数据块,就可以做到并发访问了,想要访问这个数据块就必须先经过信号量,申请成功就访问,申请失败就挂起
  3. 有了信号量的存在,最终形成的效果是,在访问公共资源前要先访问信号量,有了信号量的运行才能访问公共资源,所以两个进程之间创建了一个共享内存,并且两个进程都相互挂接到了这个共享内存上,因为信号量的存在,所以在进行内存访问前,要先向信号量申请,再对内存进行访问,在这个过程中,其实也能看出,信号量也是一种公共的资源,这两个进程都能看到这块资源,也算是完成了一种进程间通信,因为让不同的资源都看到了信号量的存在,信号量是由操作系统提供的,操作系统如何让两个进程看到同一个信号量?因此操作系统就把信号量也纳入了进程的ipc体系中,所以对应不同的进程,每申请一份资源,就意味着可以被申请的资源少了一份,其他的进程也都能知道,这就得益于信号量的存在,因此对于数据通信来说,它的目的并不一定都是为了进程数据传输,也可以通过一个计数器来帮助更合理的完成其他的进程间通信,因此才有了创建信号量需要一个key值,只要有同一个key值,才能做到让不同的进程看到同一份资源
  4. 下一个问题是,每一个进程在访问公共资源之前,都要先申请信号量,所以也就意味着信号量本身也是一种公共资源,那假设现在有1000个进程要访问同一块空间,这个空间只允许10个进程进行访问,在一瞬间有1000个进程同时访问信号量要申请空间,信号量只允许10个,所以一瞬间就申请结束了,因此信号量本身作为管理公共资源的资源,它自己也变成了公共资源,那这怎么办呢?结论是,得益于它内部的实现方式遵循原子性,对于一个进程来说,要不然不申请,要申请就必须有一个结果,可以申请或者被挂起

信号量的基本结构

因此对于未来操作系统中的信号量来说,它里面至少要存储的信息有一个计数器count,还需要有一个PCB对应的指针来维护需要被挂起的进程,这个就叫做等待队列,当一个进程要申请信号量,就让count–,如果count变成0了,就把这个进程从运行队列中剥离出来,把状态改成阻塞,再放到等待队列中进行等待,当有一个进程结束了自己的工作,从公共资源中出来了,此时就把等待队列中的进程唤醒,让它从等待队列中出来,再放到运行队列中,这样就实现了操作系统的调度功能

总结

信号量本质上也是需要被多个进程看到的,所以说信号量本身也是一种公共资源,它是一种资源的预定机制,属于进程间通信的一种,信号量由于也是一种公共资源,所以要保证自身的安全性,因此在对于资源申请的pv操作(p操作指的是申请资源,count–,v操作指的是释放资源,count++)必须要有原则,这也就是为什么信号量有pv操作,究其原因是它也要保证自身的安全

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloudStream整合MQ

目录 概念 快速搭建SCS环境 一秒切换MQ 组件 1. Binder 2. Binding 3. Message 分组消费 概念 Spring Cloud Stream(SCS) 的主要目标是一套代码,兼容所有MQ, 降低MQ的学习成本,提供一致性的编程模型,让开发者能更…

数据可视化练习

文章目录 试题示例 试题示例 绘制下图所示的表格 根据下表的数据,将班级名称一列作为x轴的刻度标签,将男生和女生两列的数据作为刻度标签对应的数值,使用bar()函数绘制下图所示的柱形图。 方式一 import numpy as np import matplotlib.p…

web自动化搞定文件上传

🔥 交流讨论:欢迎加入我们一起学习! 🔥 资源分享:耗时200小时精选的「软件测试」资料包 🔥 教程推荐:火遍全网的《软件测试》教程 📢欢迎点赞 👍 收藏 ⭐留言 &#x1…

Spring 学习1

1、什么是Spring Spring 是一款主流的 Java EE 轻量级开源框架 ,Spring 由“Spring 之父”Rod Johnson 提出并创立,其目的是用于简化 Java 企业级应用的开发难度和开发周期。Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言…

AI算力专题:算力系列之四-各省算力规划建设梳理-绿色低碳高质量发展-部署算力建设AI产业研究

今天分享的是AI算力系列深度研究报告:《AI算力专题:算力系列之四-各省算力规划建设梳理-绿色低碳高质量发展-部署算力建设AI产业研究》。 (报告出品方:中泰证券) 报告共计:40页 数据中心能耗情况 随着越…

java的面向对象编程(oop)——认识接口

前言: 打好基础,daydayup! 接口 接口概述 java提供一个关键字interface,用这个关键字可以定义出特殊结构:接口 接口格式: public interface 接口名{//成员变量(常量)//成员方法(抽…

Dragons

题目链接&#xff1a; Problem - 230A - Codeforces 解题思路&#xff1a; 用结构体排序就好&#xff0c;从最小的开始比较&#xff0c;大于就加上奖励&#xff0c;小于输出NO 下面是c代码&#xff1a; #include<iostream> #include<algorithm> using namespac…

【2024.1.30练习】李白打酒加强版(25分)

题目描述 题目思路 在最多数据的情况下&#xff0c;有100个店100朵花&#xff0c;总情况为的天文数字&#xff0c;暴力枚举已经不可能实现&#xff0c;考虑使用动态规划解决问题。最后遇到的一定是花&#xff0c;所以思路更倾向于倒推。 建立二维数组&#xff0c;容易联想到为…

软件个性化选型:制造企业如何选择适合自身的工单管理系统-亿发

企业制造业是实体经济中非常重要和基础的组成部分&#xff0c;直接关系到国家经济的血脉。然而&#xff0c;传统制造业在生产与管理上所采用的老一套方法和经验已不再适应当下的发展需求。信息化、数字化和智能化被视为制造企业的必然趋势。要想在竞争激烈的市场中永立潮头&…

都2024年了,谁还在逛良品铺子?

作者 | 辰纹 来源 | 洞见新研社 2019年年初&#xff0c;良品铺子举办了一场高端零食战略发布会&#xff0c;当时还花重金请来顶流明星为品牌代言&#xff0c;在强化“高端零食”定位的同时&#xff0c;良品铺子坚定的表示&#xff0c;要“抛弃价格战”。 时任良品铺子董事长杨…

24小时涨粉10w+的AI小游戏-哄哄模拟器

近年来&#xff0c;随着chatGPT的爆火&#xff0c;一系列的AI应用应运而生。比如&#xff1a;AI绘画&#xff0c;AI写作等。今天我们来看看最近很火的一个AI小游戏-哄哄模拟器。 1. 试玩体验 这款游戏名叫“哄哄模拟器”&#xff0c;体验地址为&#xff1a;https://hong.grea…

RGMII接口介绍

RGMII接口概述 RGMII全称为Reduced Gigabit Media Independent Interface&#xff0c;是一种网络接口标准&#xff0c;用于千兆以太网芯片与PHY芯片之间的接口标准。RGMII接口的设计目的是为了减少I/O的数量&#xff0c;尽可能减小网卡PCB占用面积&#xff0c;同时提高数据传输…

Nacos服务注册源码:客户端

入口 我们就拿nacos自己example下的NamingExample来做测试 public class NamingExample {public static void main(String[] args) throws NacosException, InterruptedException {Properties properties new Properties();properties.setProperty("serverAddr", …

如何在DBeaver中重命名数据库

前言 DBeaver是一款强大的开源通用数据库管理和开发工具&#xff0c;支持多种数据库类型。在某些数据库系统中&#xff0c;你可以直接通过DBeaver的图形界面来重命名数据库名称。本文将详细介绍如何在DBeaver中进行数据库重命名操作。 重要提示&#xff1a; 对于不同的数据库…

Leetcode—2396. 严格回文的数字【中等】

2024每日刷题&#xff08;一零六&#xff09; Leetcode—2396. 严格回文的数字 算法思想 实现代码 class Solution { public:bool isStrictlyPalindromic(int n) {return false;} };运行结果 之后我会持续更新&#xff0c;如果喜欢我的文章&#xff0c;请记得一键三连哦&…

vue2 国际化的使用,自动翻译文件,自动生成国际化文件

vue2 国际化的使用&#xff0c;自动翻译文件&#xff0c;自动生成国际化文件 npm i vue-i18n6 文件代码 // zh.js 用来写全局通用的国际化 export default {home:"首页" }//en.js 用来写全局通用的国际化 export default {home:"home page" }//kor.js …

窗口函数rows between 、range between的区分

【移动窗口】 移动窗口&#xff0c;顾名思义&#xff0c;“窗口”&#xff08;也就是操作数据的范围&#xff09;不是固定的&#xff0c;而是随着设定条件逐行移动的。 在over后面的子句中&#xff0c;使用rows加“范围关键字”可以设置移动窗口&#xff0c;语法如下&#xf…

ESP32 看门狗:保障系统稳定运行的重要机制

ESP32 看门狗&#xff1a;保障系统稳定运行的重要机制 导言&#xff1a; 在嵌入式系统开发中&#xff0c;系统稳定性是至关重要的。为了应对系统出现异常情况或者死锁等问题&#xff0c;ESP32提供了看门狗&#xff08;Watchdog&#xff09;机制。本文将深入探讨ESP32看门狗的工…

内网穿透的应用-如何搭建FastDFS文件服务器并实现无公网ip访问本地文件服务

文章目录 前言1. 本地搭建FastDFS文件系统1.1 环境安装1.2 安装libfastcommon1.3 安装FastDFS1.4 配置Tracker1.5 配置Storage1.6 测试上传下载1.7 与Nginx整合1.8 安装Nginx1.9 配置Nginx 2. 局域网测试访问FastDFS3. 安装cpolar内网穿透4. 配置公网访问地址5. 固定公网地址5.…

Docker的优化和私有容器的部署管理

1 Docker的优化和配置调整 1.1 如何缩小镜像的体积大小 1&#xff09;尽可能使用小体积的基础镜像&#xff08;一般推荐使用alpine阿尔卑斯镜像&#xff09; 2&#xff09;尽可能的减少dockfile指令的数量从而来减少镜像的层数 3&#xff09;在RUN指令末尾添加安装软件后清…