常见的IO模型

news2024/11/17 3:41:46

计算机硬件包括CPU,内存,网卡

为了避免用户应用和操作系统内核产生冲突乃至内核崩溃,用户应用和内核是隔离开的

1)进程的寻址空间会被划分成两部分,内核空间和用户空间,内核和用户应用都无法直接访问物理内存,而是给他们分配不同的虚拟内存地址空间映射到不同的物理内存,应用或者内核在访问虚拟地址内存空间的时候,其实就需要一个虚拟的地址了,这个地址是一个无符号的整数,从0开始,最大值取决于CPU地址总线和寄存器的带宽

2)假设一个32位的系统,他的地址的最大值就是2^32,寻址的范围就是从0-2^32,内存地址的每一个值代表的就是一个存储单元,也就是一个字节,所以2^32这么大的寻址空间

用户空间只能执行受限的命令,并且不能调用系统资源必须通过内核提供的接口来进行访问

内核空间可以执行特权命令,调用一切系统资源

linux系统为了提升IO效率,会在用户空间和内核空间都加入一个缓冲区:

用户进程想要在写数据的时候,要把用户缓冲区数据拷贝到内核缓冲区里面然后再写入设备

读数据的时候,要从设备中读取数据到内核缓冲区,然后再将内核缓冲区数据拷贝到用户缓冲区

性能瓶颈:

1)等待内核寻址磁盘,如果要读取网卡,不光要寻址还需要等待别人发送数据过来,因为网卡本身就是别人通过网络发送过来的数据,最终也就是硬件将数据准备好放到内核缓冲区中

2)数据拷贝:内核缓冲区将内核缓冲区的数据拷贝到用户缓冲区里,或者是用户缓冲区的数据拷贝到用户缓冲区;

 

阻塞IO:就是两个阶段都需要阻塞等待

等待数据的结束条件:只要内核将磁盘数据或者其他硬件设备上的数据读取到内核缓冲区

最终可以看到,在阻塞IO模型中,用户进程在两个阶段都是阻塞状态

非阻塞IO:非阻塞IO的recvfrom操作会立即返回结果而不是阻塞用户进程

用户进程在第一阶段是频繁调用recvfrom操作的,直到操作系统内核将磁盘或者网卡的数据准备好,也就是写到内核缓冲区里面,这个过程用户进程是不会发生阻塞的,但是在第二个阶段,当操作系统内核将数据从内核缓冲区拷贝到用户空间,这个过程是阻塞的

但是可以看到,在非阻塞IO模型中,用户进程在第一个阶段是非阻塞,但是却是一个不断尝试的过程,和阻塞IO一样,这段期间用户进程并没有做什么有意义的事情,也是相当于忙等,况且因为非阻塞IO一直重试,就会导致频繁调用系统调用,会使CPU的使用率暴增

IO多路复用:只是使用一个服务器进程从而同时处理多个套接字描述符链接

 

 

无论是阻塞IO还是非阻塞IO,用户应用在第一阶段都需要调用recvfrom(尝试读取数据)来进行获取数据,差别在于没有数据的时候的处理方案:

1)如果调用recvfrom,恰好没有数据,阻塞IO会使进程进入到阻塞状态,非阻塞IO会使CPU空转,一直尝试进行系统调用,所以他们都不能充分发挥CPU的作用

2)如果调用recvfrom,恰好有数据,那么用户进程会直接可以进入到第二阶段,读取并处理数据

比如说服务器端处理客户端的Socket请求的时候,在单线程情况下,只能依次处理一个Socket,如果说正在处理的socket没有就绪,数据不可读或者不可写,线程就会被阻塞,所有的其他Socket客户端都必须等待,性能自然非常差;

这个过程就类似于说服务员给顾客进行点餐,一共分成两步:

1)顾客要思考吃什么?也就是等待对应的数据就绪

2)顾客想好了,开始进行点餐,读取数据

想要进行提升效率,一共有两种方法:

1)增加更多的服务员,多线程进行执行

2)不进行排队,谁想好了吃什么(数据就绪了),服务员就给谁点餐(用户应用就去读取数据)

那么用户进程该如何知道内核中的数据是否就绪呢?

每一个客户端和服务器建立连接的时候,都会有一个网络套接字Socket,都有一个对应的文件描述符

​​​​​​​

 

文件描述符:简称为FD,是一个从0开始递增的无符号整数,用来关联linux系统中的一个文件,在linux系统中一切都是文件,例如常规文件,视频,硬件设备,还包括网络连接套接字

IO多路复用:是利用单个线程去监听多个FD,并在某一个FD可读,可写的时候得到通知,从而避免进行无效的等待,充分利用CPU资源

 

1)首先用户应用想要读取数据的时候首先调用的是select函数,不再是recvfrom函数了,recvfrom是直接尝试读取FD的数据,但是我们不知道当调用FD的时候数据是否就绪,如果你调用recvfrom的时候,FD中的数据没有等待就绪,这个用户进程就不得不阻塞等待;

2)每一个用户客户端Socket将对应的FD传递给Select函数,Select函数将FD传递到操作系统内核,然后操作系统内核就会监听多个FD,只要有任意一个FD就绪,直接就会通知对应的Socket客户端,这个操作系统内核监听FD的过程中,如果没有FD准备就绪,那么所有的用户进程都会阻塞等待,如果有多个FD就绪,就会直接通知;

3)此时对应的Socket客户端就去调用recvfrom读取数据,况且一定是不会读取数据阻塞的(多个Socket如果被同时通知,同时也会排队去执行recvfrom系统调用)

1)每一个人都在一个桌子上,服务员上面有一盏大灯,只要有顾客准备好点餐了,每一个顾客的桌子上都有一个开关,顾客准备好只需要按下开关就可以了,但是如果有任意一个顾客按下开关了,那么灯泡是一定会亮的

但是如果灯泡亮了,服务员就会寻找每一位按下按钮的顾客,需要进行遍历

2)现在不采用灯泡的模式了,而是直接在电脑上显示,如果又用户按下开关了,那么电脑上就直接显示出对应的用户记录,就不需要一个一个的进行遍历了;

select和poll只会通知用户进程有FD就绪了,但是不确定到底是哪一个FD,需要用户进程进行逐个遍历FD来进行确认,epoll则会在用户ID就绪的同时,就直接把已经就绪的FD写入到用户空间;

IO多路复用select:监听多个FD的集合

1)select函数中nfds,传递的最大的FD的值,等于是进行遍历的时候,FD的一个最大上限,FD的只是一个无符号整数,从0开始向上递增,指定这个值就是告诉内核,你进行遍历的FD就是最后一个FD;

2)select函数的监听集合*readfds,linux系统把可能发生的IO事件分为了三类

3)timeout代表操作系统FD要等待多久,超过等待事件之后返回,然后继续调用下一次Select继续检测FD;

1)用户态会首先进行创建fdset的集合,fdset结构非常特殊,里面有一个fdsbits属性,类型就是一个fdmask*数组,数组大小是有两个常量进行计算,最终是1024个比特位

2)reds表示要进行读取的内核数据的数组,会使用1024个比特位,可以监听1024个FD,0表示未监听,1表示监听,在刚进行创建的时候,每一个fds比特位都会被初始化成0;

3)假设此时要监听1 2 5,那么fds_bit的结构就类似于是:

4)用户进程开始调用系统调用select函数(5+1,rfds,null,null,3),第二个参数是要监听的读事件的fd集合;

5)当用户进程执行select函数的那一刻,用户进程就把对应的rfdbits传递到内核空间,这就涉及到了用户态和内核态的切换,涉及到数据的拷贝

6)操作系统内核就会遍历这个fds集合,来监听对应的fd是否就绪

7)如果没有就绪,直接进行休眠,如果就绪了,内核就会将结果写到fd集合里面去了,内核就去再次进行遍历fd,就绪的直接保留,未就绪的直接清0,此时fd集合中保存的就是就序的fd,然后selcet的返回值就直接返回一个数字,代表有几个fd就绪了,此时select函数只是返回给用户进程有几个fd就绪了,但是并没有返回哪一个FD就绪了;

8)操作系统内核再将这个fds_bits集合重新拷贝返回给用户进程覆盖用户空间里面的fds集合

9)用户进程再次遍历fds中的比特位,然后对应的socket就去开始读取对应的数据,如此循环再次执行步骤2,反复执行,处理各种而样的Socket去读取数据

SelcetIO多路复用的缺点:

1)需要将整个fd_set从用户空间拷贝到内核空间,select结束之后还要将fd_set再次拷贝会用户空间,每执行一次select,就会涉及到两次用户态到内核态的切换,两次内存的拷贝,select函数在循环往复地执行,就回来会的拷贝;

2)select无法得知具体是哪一个fd就绪,需要遍历整个fdset

3)fd_set监听的fd数量不能超过1024个

IO多路复用poll:

poll模式针对于select模式做了一些简单改进,但是性能提升不明显,关键代码如下

 

1)poll函数里面,第一个参数fds表示操作系统内核监听的fd的集合,可以进行自定义大小

2)poll函数的第二个参数nfds代表数组中元素的个数,第三个参数是超时时间

pollfd又是一个结构体,这里没有使用二进制位来直接标注fd

第一个参数是要监听的fd,第二个参数是要监听的事件类型,第三个参数是真正发生的事件类型,在进行调用poll函数的时候,只需要传递前两个参数即可,第三个参数是由操作系统内核来进行设置的,如果内核发现数据有就绪的情况就将revents设置成1,否则设置成0;

IO流程:

1)创建pollfd数组,向其中添加关注的fd信息,数组大小自定义

2)调用poll函数,将pollfd数组拷贝到内核空间,转成链表存储,是没有上限的

3)内核进行遍历fd,查看是否就绪

4)数据就绪或者超市以后,会拷贝pollfd数组到用户空间,返回就绪的fd数量是n

5)用户进程会进行判断N是否大于0,如果大于0就直接遍历pollfd数组,找到就绪的fd

poll相比于select来说,select中的fd_set大小上限是1024个,但是pollfd在内核中采用的是链表,是没有上限的,但是这并没有带来性能上的提升,监听的FD越多,每一次进行遍历消耗的时间也就越多,性能反而会下降

IO多路复用:epoll 

1)首先会在用户空间调用epoll_create函数然后操作系统内核里面创建eventpoll结构体,在这个结构体里面包含了一棵红黑树,在这里面记录了要监听的FD,还有一个字段rdlist链表表示就绪的FD;

2)此时rb_root和list_head都是null,向用户空间返回的句柄就是eventpoll的唯一身份标识

3)然后用户空间会调用一个函数epoll_ctrl()函数,添加要监听的FD,关联epoll_create()函数返回的句柄,第一个参数是epoll实例的句柄,表明要将fd要添加到哪一个eventpoll里面,第二参数op表示要执行的操作,可以是新增操作,就是将当前指定的fd添加到eventpoll里面,也就是对应的红黑树上面(红黑树上面是记录着所有要进行监听的FD的),也可以进行删除,这个fd不想进行监听了,就从红黑树上移除,还可以进行修改fd的类型,但是在做初始化的时候一定是进行新增操作,将需要监听的fd给加入到红黑树里面;

4)我们不仅要把多个fd添加到红黑树上面,而且要给每一个要进行监听的fd以及要监听的事件类型添加上一个回调函数ep_poll_callback,这个回调函数会在对应的fd对应的事件就绪的时候会自动触发,一旦这个回调函数触发之后,操作系统内核就会将对应的FD添加到就绪列表中;

5)用户进程最终还要调用一个epoll_wait函数,这个函数就是为了等待FD就绪,这个函数里面指定了四个参数,第一个参数是eventpoll实例的句柄,来标识唯一一个eventpoll,第二个参数是events数组的指针,用来接收eventpoll中就序的FD,第三个参数是这个events空数组所能接受的最大的空间,第四个参数是超时时间,因为epoll_wait函数的主要功能就是去等待就绪的FD,所以timeout就是等待的最大时间;

6)当我们执行epoll_wait函数的时候,操作系统内核就会去检查不是去检查红黑树,因为随着程序运行时间的增长,红黑树上面的FD的节点会越来越多,内核是去直接检查就序列表,因为一旦FD就绪了,里面的回调函数就会将这个FD添加到list_head里面,如果就绪列表中存在FD,那么epoll_wait函数直接返回FD的数量,如果list_head中没有元素,那么直接等待timeout时间,如果在超过这个时间还是list_head中还是没有FD,那么这个函数直接返回0;

如果list_head中存在fd,那么会把fd拷贝到用户空间,并将fd从list_head终端开

1)之前学过的select模式问题就是每一次调用select,都需要把要监听的FD数组或集合都要拷贝到操作系统内核里面,select函数执行完后最终还要把这个数组拷贝回用户空间

2)但是在epoll模式中,把select函数的功能拆分成了两份,select函数主要是做三件事,把fd数组从用户空间拷贝到内核,等待fd就绪,将二进制数组从内核空间拷贝到用户空间

3)在epoll中,会调用epoll_ctl会将fd从用户空间拷贝到内核空间,epoll_wait最终才是等待fd就绪,对于每一个fd来说只需要执行一次epoll_ctl函数即可,而只需要循环调用epoll_wait方法,返回对应的fd即可,不需要将fd进行拷贝,相比于select来说,减少了无数次fd数据的拷贝,减少了拷贝次数;

4)在select和poll模式中,需要将内核中所有的fd都拷贝回用户空间,无论是就序的fd还是没有就序的fd,还需要进行遍历,但是在epoll模式中,只是拷贝了就绪的fd,未就绪的不用管,相比于select模式和poll模式拷贝的数据都少了很多,减少了拷贝的数量,况且不需要再进行遍历了,这样就可以保证数组中拿到的每一个fd都是已经就绪的fd,效率更高;

5)在select模式中,最终只能监听1024个fd,而poll模式虽然改成了链表,监听fd的数量是没有上限的,但是这只能说明理论上没有上线,如果fd的数量非常非常多,链表就特别长,那么遍历的时间也非常久,受限于性能,实际上是有限的;

但是在epoll中,用户添加的所有fd都会添加到红黑树上,红黑树所能支持的数量是无限多的,红黑树的增删改查的性能不会随着节点数量的增加和减少有较大的波动,查找效率很高

总结:

一)select模式存在的三大问题:

1)能进行监听的FD的数量不超过1024

2)每一次select都要把所有要监听的FD都拷贝到内核空间

3)每一次用户进程都需要遍历所有的FD来进行判断就绪状态

二)poll模式中所解决的问题:

poll中的链表解决了select模式中监听的FD上限的问题,但是仍然要遍历所有的FD,如果监听过多,那么性能会直接下降

三)epoll模式种是如何解决这些问题的?

3.1)基于epoll实例中的红黑树要保存监听的FD,况且理论上没有上限,而且性能不会随着监听的FD的数量增多而下降;

3.2)每一个FD只需要执行一次epoll_ctl添加到红黑树,以后每一次epol_wait无需传递任何参数,无需重复拷贝FD到内核空间;

3.3)内核会将就绪的FD直接拷贝到用户空间的指定位置,用户进程无需遍历所有的FD就知道就序的FD都有谁;

IO多路复用事件通知机制:

LevelTriggered:简称为LT,当FD中有数据可读的时候,会重复通知多次,直到数据处理完成,这是Epoll的默认处理方式,通知完成之后,不会将list_head中的节点移除掉,但是重复的通知会对性能产生很大的影响,只要调用epoll_wait就会通知用户;

EdgeTriggered:简称为ET,当FD中有数据可读的时候,只会被通知一次,不管数据是否已经完成,通知完成之后直接将list_head种的节点移除掉;

1)ET模式为了解决这个问题,可以在步骤四加上一个循环循环读取FD中的数据,但是只能采用非阻塞IO的方式,因为如果采用阻塞IO的方式来读,一旦FD中的数据没了,不是返回一个错误,而是采用一直等待的方式,直到下一次FD中来数据位置,就会导致进程阻塞;

2)所以要想再一次通知中读取所有数据,那么就需要采用循环的方式并且要采用非阻塞IO读取,读取到了数据会返回,如果读取不到数据也会返回,只不过是告诉你一个标识,然后就可以根据这个标识退出循环,这样就解决了循环读取阻塞的问题;

 IO多路复用-web服务流程

1)要么是客户端来连接的事件,直接读取ssfd即可,直接和客户端建立连接并且监听就可以

2)要么是客户端数据可读,直接返回对应的客户端的Socket的fd即可,读取客户端Socket中的数据处理响应并返回即可

3)要么是异常,也需要将结果报错信息写回到客户端Socket即可

1)当服务端启动的时候,用户进程就去调用系统调用函数epoll_create来创建实例,会在操作系统内核中创建一颗红黑树,来记录监听的FD,创建一个链表用来记录就序的FD;

2)用户进程创建初始化ServerSocket,在TCP中,服务端就是一个TcpServerSocket,他也会有自己的文件描述符,也是一个FD,称之为是ssfd,接下来进行系统调用函数epoll_ctrl,指定epoll_trl的类型op属性标记为新增即可,将这个FD注册到epoll_create中,并加入到红黑树里面,还会给添加到红黑树的FD绑定一个回调函数,也就是ep_poll_callback,未来FD就绪的时候,这个回调函数就会立即执行,就会将就绪的FD添加到list_head链表中;

3)接下来用户进程会调用系统调用函数epoll_wait来等待FD就绪,里面的epfd指向特定的eventpoll,如果等待指定时间后eventpoll里面的list_head中仍然没有元素就会直接返回,如果等待的时间里面,list_head中有元素那么就直接将FD返回到epoll_wait中的events,也就是将对应的FD返回给了用户空间,然后会循环执行epoll_wait来检查是否有FD就绪;

4)FD就绪的时间:作为ServerSocket来说,只有当客户端Socket在向ServerSocket申请连接的时候,因为ServerSocket就是来接收客户端的请求的,ServerSocket的FD就会产生就绪,而且是读事件;

5)但是随着程序的运行,epollevent中的list_head上面所监听的FD实例也会越来越多,事件的类型也会越来越多,所以还要进行判断事件的类型是什么?如果类型是epoll_in,说明真的是一个读事件况且是ssfd可读说明有当前客户端尝试进行连接,ServerSocket于是就调用accept()方法接收客户端的socket,得到客户端Socket对应的FD,然后再把这个客户端Socket对应的FD注册到红黑树里面,还要注册回调函数,循环往复;

6)随着时间的推移,连接到ServerSocket中的客户端越来越多,监听到的FD也越来越多

7)当一个客户端发送请求给ServerSocket过来,就会触发FD就绪,当然也是一个读事件,当然这里的事件有两种,一种是ssfd可读(表明有客户端建立连接),另外一种是只是读取普通的客户端Socket的发送请求的读取,如果是后面这种,就直接读取对应的fd,处理请求,等到业务处理完成,写到客户端Socket里面即可;

信号驱动IO:

信号驱动IO是和内核建立SIGIO的信号关联并且设置回调,当内核中有FD就绪的时候,就会发出SIGIO信号来通知用户,期间用户应用可以执行其他业务,不需要进行阻塞等待

用户一上来并不会调用recvfrom,而是一个sigaction的指令,就去向内核中指定一个fd,并向其绑定一个信号处理的函数,直接立即结束,这个期间不会阻塞等待,直到数据就序的时候,操作系统内核就会直接递交SIGIO信号,用户进程就直接进行处理;

缺点:当有大量的IO操作的时候,信号比较多,SIGIO处理函数不能及时处理可能会导致信号队列溢出,况且内核空间和用户空间的频繁信号交互性能也比较低,这种模式在并发的场景下会出现一定的问题;

异步IO:可以看到异步IO在两个阶段,用户进程都是处于非阻塞状态

1)在整个过程中根本就没有调用recvfrom这个函数,也就是没有调用数据拷贝的函数,直接调用了一个aioread函数,这个函数是直接告诉系统内核,要读哪一个FD,要读到哪里去,然后操作系统内核直接返回了OK,用户进程就去干别的事情去了

2)然后当fd数据准备完成了,操作系统内核就感知到了,于是就将内核缓冲区的数据自动的拷贝到用户缓冲区里面,拷贝完成之后,操作系统内核就会提交aio_read中的信号返回给信号处理函数处理数据,直接操作系统内核一条龙服务,第一阶段和第二阶段都是有操作系统内核来完成的,用户啥也不需要管;

缺点:因为用户进程不需要阻塞,就会频繁进行处理用户的请求,新的请求过来有需要调用io_read通知内核来完成数据拷贝,这个时候很有可能操作系统内核还没有完成上一次用户的请求,循环往复,在高并发的情况下,用户进程不停地将请求传递给内核,让内核进行处理,这样内核积累的IO读写的任务会越来越多,效率也越来越低,最终可能会导致系统崩溃,如果想要做异步IO,那么必须做好对并发访问的限流,实现起来相对比较繁琐;

IO操作是同步还是异步,关键是看数据在用户空间和内核空间的拷贝过程(数据读写的IO操作),也就是两个阶段是同步还是异步

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

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

相关文章

【Vue】Vuex,Vue-Router

❤️ Author: 老九 ☕️ 个人博客:老九的CSDN博客 🙏 个人名言:不可控之事 乐观面对 😍 系列专栏: 文章目录 Vuexvue-router Vuex 将公用的数据统一存放在store(全局数据中心)中,实现更方便的跨…

从实习到秋招成为一名安全工程师,我经历了什么

前言 借朋友口述总结了安全招聘面试经历分享,希望更多的人看到这篇文,从中得到启发,找到自己心仪的工作。 基本情况 签了字节的三方,秋招终于告一段落。从八月份边实习边准备秋招到现在,经历了许多,这篇帖…

2023金三银四Java开发岗热门面试题总结

最近很多粉丝朋友私信我说:熬过了去年的寒冬却没熬过现在的内卷;打开 Boss 直拒一排已读不回,回的基本都是外包,薪资还给的不高,对技术水平要求也远超从前;感觉 Java 一个初中级岗位有上千人同时竞争&#…

都说00后已经躺平了,但是有一说一,该卷的还是卷啊。

这不,三月份春招我们公司来了个00后,工作没两年,跳槽到我们公司起薪20K,都快接近我了。 后来才知道人家是个卷王,从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天,原来这位小老弟家里条件不太好&…

Java学习路线(21)——网络通信

一、网络通信三件套 1、IP地址: 设备在网络中的地址,唯一标识 概念: Internet Protocal,简称为IP,全称“互联网协议地址”。 常见分类: IPv4(32位) 和 IPv6(128位&#…

IDEA debug断点调试认识与技巧

IDEA debug断点调试认识与技巧 文章目录 IDEA debug断点调试认识与技巧认识debug常见的操作如何开启debug模式 基本用法和快捷键1、显示执行点(Alt F10)2、步过(F8)3、步入(F7)4、强制步入(Alt…

【容器云架构】确定容器网络calico最佳网络选项

大图 了解 Calico 支持的不同网络选项,以便您可以根据需要选择最佳选项。 价值 Calico 灵活的模块化架构支持广泛的部署选项,因此您可以选择适合您特定环境和需求的最佳网络方法。这包括使用各种 CNI 和 IPAM 插件以及底层网络类型以非覆盖或覆盖模式运行…

线性回归模型一二三

文章目录 什么是线性回归线性回归的求解一元线性回归(最小二乘法)多元线性回归 衍生求解梯度下降智能搜索算法求解(PSO)简要分析 线性回归与简单神经网络联系类比推导反向传播 总结 什么是线性回归 线性回归的基本假设是&#xf…

Java JUC并发编程调优

前言 1、JUC是指有关 java.util.concurrent包以及其子包,这些包都是有关线程操作的包 2、HTTPS服务请求中,WEB服务只负责创建主线程来接收外部的HTTPS请求,如果不做任何处理,默认业务逻辑是通过主线程来做的,如果业务…

预训练大语言模型的三种微调技术总结:fine-tuning、parameter-efficient fine-tuning和prompt-tuning

预训练大模型,尤其是大语言模型已经是当前最火热的AI技术。2018年Google发布BERT模型(BERT在DataLearner官方模型卡信息:https://www.datalearner.com/ai-models/pretrained-models/BERT )的时候,大家还没有意识到本轮…

国际植物命名数据库(International Plant Names Index)

功能介绍 https://www.ipni.org/ 是国际植物命名数据库(International Plant Names Index)的官方网站。国际植物命名数据库是一个全球性的植物命名和分类资源,旨在提供植物命名信息的权威来源。以下是该网站的一些特点和功能: 植…

wmvcore.dll丢失怎么弄?解决wmvcore.dll丢失问题

wmvcore.dll是Windows Media Player中的一个重要组件,它负责处理视频和音频文件的编码和解码。如果您在使用Windows Media Player或其他媒体播放器时遇到了wmvcore.dll丢失的问题,那么您可能无法播放视频或音频文件。在这种情况下,您可以使用…

干货|接口测试必备技能-常见接口协议解析

【摘要】 服务与服务之间传递数据包,往往会因为不同的应用场景,使用不同的通讯协议进行传递。比如网站的访问,常常会使用 HTTP 协议进行传递,文件传输使用 FTP,邮件传递使用 SMTP。上述的三种类型的协议都处于网络模型…

电流环参数自整定及其原理

前言 电流环参数自整定是通过程序计算电流环PI调节器增益以实现环路响应仅受用户设定PI调节器带宽影响,而和电机本身参数无关的目的。 本文分析电流环参数自整定背后的原理,并通过仿真进行验证。 1、永磁同步电机dq轴数学模型 本文提到的电流环参数自…

【论文总结】Creating a Secure Underlay for the Internet

为互联网创建一个安全的底层 摘要: 对手可以利用跨域路由漏洞拦截通信并破坏关键互联网应用的安全性。与此同时,部署诸如边界网关安全协议(BGPsec)和下一代网络上的可扩展性、控制和隔离(SCION)等安全路由…

38 KVM管理设备-管理虚拟机USB

文章目录 38 KVM管理设备-管理虚拟机USB38.1 配置USB控制器38.1.1 概述38.1.2 注意事项38.1.3 配置方法 38.2 配置USB直通设备38.2.1 概述38.2.2 注意事项38.2.3 配置说明38.2.4 配置方法 38 KVM管理设备-管理虚拟机USB 为了方便在虚拟机内部使用USBkey设备、USB海量存储设备等…

蓝桥杯单片机基础模板一:动态数码管显示

蓝桥杯单片机有一些基础模块的写法,他是没有一定的公式模板的。 好比动态数码管扫描显示,原理就是快速地 传输段选和位选。 但因为电路上添加了74HC573芯片,导致了我们移植别处 51单片机的动态扫描代码 会出现诸多问题,比如闪烁…

期末学习总结模板

期末学习总结精选篇1 转眼间研究生的生活已经有一学期了,感觉才参加复试没多久,回头想想,这一年过的真快,因为生病,耽误了很多时间,收获太少,遗憾太多。 本学期的收获: 1、暑假里看了…

Elasticsearch文件存储

分析Elasticsearch Index文件是如何存储的? 主要是想看一下FST文件是以什么粒度创建的? 首先通过kibana找一个索引的shard,此处咱们就以logstash-2023.05.30索引为例 查看下shard分布情况 GET /_cat/shards/logstash-2023.05.30?vindex …

AtCoder Beginner Contest 303——A-E题讲解

蒟蒻来讲题,还望大家喜。若哪有问题,大家尽可提! Hello, 大家好哇!本初中生蒟蒻讲解一下AtCoder Beginner Contest 303这场比赛的A-E题! A - Similar String 原题 Problem Statement Two characters x x x and y…