五种网络IO模型详解

Visual Studio调试技巧与实用方法总结(实战经验分享) 本文根据多年的项目实战经验,详细介绍一些Visual Studio常用的高效调试手段与技巧。 阅读详情

一 IO操作本质

数据复制的过程中不会消耗CPU

# 1 内存分为内核缓冲区和用户缓冲区

# 2 用户的应用程序不能直接操作内核缓冲区,需要将数据从内核拷贝到用户才能使用

# 3 而IO操作、网络请求加载到内存的数据一开始是放在内核缓冲区的

 

文章相关视频讲解:

C/C++ Linux服务器开发高级架构学习视频点击:C/C++Linux服务器开发高级架构/Linux后台架构师-学习视频

90分钟搞定底层网络IO模型,必须要懂得10种模型

epoll原理剖析以及reactor模型应用

二 IO模型

1. BIO – 阻塞模式I/O

用户进程从发起请求,到最终拿到数据前,一直挂起等待; 数据会由用户进程完成拷贝

'''
举个例子:一个人去 商店买一把菜刀,
他到商店问老板有没有菜刀(发起系统调用)
如果有(表示在内核缓冲区有需要的数据)
老板直接把菜刀给买家(从内核缓冲区拷贝到用户缓冲区)
这个过程买家一直在等待

如果没有,商店老板会向工厂下订单(IO操作,等待数据准备好)
工厂把菜刀运给老板(进入到内核缓冲区)
老板把菜刀给买家(从内核缓冲区拷贝到用户缓冲区)
这个过程买家一直在等待
是同步io
'''

 

import socket


server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)


while True:
    conn, addr = server.accept()
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0:break
            print(data)
            conn.send(data.upper())
        except ConnectionResetError as e:
            break
    conn.close()
    
# 在服务端开设多进程或者多线程 进程池线程池 其实还是没有解决IO问题	
该等的地方还是得等 没有规避
只不过多个人等待的彼此互不干扰

2. NIO – 非阻塞模式I/O

用户进程发起请求,如果数据没有准备好,那么立刻告知用户进程未准备好;此时用户进程可选择继续发起请求、或者先去做其他事情,稍后再回来继续发请求,直到被告知数据准备完毕,可以开始接收为止; 数据会由用户进程完成拷贝

'''
举个例子:一个人去 商店买一把菜刀,
他到商店问老板有没有菜刀(发起系统调用)
老板说没有,在向工厂进货(返回状态)
买家去别地方玩了会,又回来问,菜刀到了么(发起系统调用)
老板说还没有(返回状态)
买家又去玩了会(不断轮询)
最后一次再问,菜刀有了(数据准备好了)
老板把菜刀递给买家(从内核缓冲区拷贝到用户缓冲区)

整个过程轮询+等待:轮询时没有等待,可以做其他事,从内核缓冲区拷贝到用户缓冲区需要等待
是同步io

同一个线程,同一时刻只能监听一个socket,造成浪费,引入io多路复用,同时监听读个socket
'''

 

"""
要自己实现一个非阻塞IO模型
"""
import socket
import time


server = socket.socket()
server.bind(('127.0.0.1', 8081))
server.listen(5)
server.setblocking(False)
# 将所有的网络阻塞变为非阻塞
r_list = []
del_list = []
while True:
    try:
        conn, addr = server.accept()
        r_list.append(conn)
    except BlockingIOError:
        # time.sleep(0.1)
        # print('列表的长度:',len(r_list))
        # print('做其他事')
        for conn in r_list:
            try:
                data = conn.recv(1024)  # 没有消息 报错
                if len(data) == 0:  # 客户端断开链接
                    conn.close()  # 关闭conn
                    # 将无用的conn从r_list删除
                    del_list.append(conn)
                    continue
                conn.send(data.upper())
            except BlockingIOError:
                continue
            except ConnectionResetError:
                conn.close()
                del_list.append(conn)
        # 挥手无用的链接
        for conn in del_list:
            r_list.remove(conn)
        del_list.clear()

# 客户端
import socket


client = socket.socket()
client.connect(('127.0.0.1',8081))


while True:
    client.send(b'hello world')
    data = client.recv(1024)
    print(data)

关于C/C++ Linux后端开发网络底层原理知识 点击 学习资料 获取,内容知识点包括Linux,Nginx,ZeroMQ,MySQL,Redis,线程池,MongoDB,ZK,Linux内核,CDN,P2P,epoll,Docker,TCP/IP,协程,DPDK等等。

3. IO Multiplexing - I/O多路复用模型

类似BIO,只不过找了一个代理,来挂起等待,并能同时监听多个请求; 数据会由用户进程完成拷贝

'''
举个例子:多个人去 一个商店买菜刀,
多个人给老板打电话,说我要买菜刀(发起系统调用)
老板把每个人都记录下来(放到select中)
老板去工厂进货(IO操作)
有货了,再挨个通知买到的人,来取刀(通知/返回可读条件)
买家来到商店等待,老板把到给买家(从内核缓冲区拷贝到用户缓冲区)

多路复用:老板可以同时接受很多请求(select模型最大1024个,epoll模型),
但是老板把到给买家这个过程,还需要等待,
是同步io


强调:
 1. 如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。
 2. 在多路复用模型中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个用户的process其实是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。
 结论: select的优势在于可以处理多个连接,不适用于单个连接
'''

 

"""
当监管的对象只有一个的时候 其实IO多路复用连阻塞IO都比比不上!!!
但是IO多路复用可以一次性监管很多个对象

server = socket.socket()
conn,addr = server.accept()

监管机制是操作系统本身就有的 如果你想要用该监管机制(select)
需要你导入对应的select模块
"""
import socket
import select

server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
server.setblocking(False)
read_list = [server]

while True:
    r_list, w_list, x_list = select.select(read_list, [], [])
    """
    帮你监管
    一旦有人来了 立刻给你返回对应的监管对象
    """
    # print(res)  # ([<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080)>], [], [])
    # print(server)
    # print(r_list)
    for i in r_list:  #
        """针对不同的对象做不同的处理"""
        if i is server:
            conn, addr = i.accept()
            # 也应该添加到监管的队列中
            read_list.append(conn)
        else:
            res = i.recv(1024)
            if len(res) == 0:
                i.close()
                # 将无效的监管对象 移除
                read_list.remove(i)
                continue
            print(res)
            i.send(b'heiheiheiheihei')

 # 客户端
import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:

    client.send(b'hello world')
    data = client.recv(1024)
    print(data)

3.1

IO复用:为了解释这个名词,首先来理解下复用这个概念,复用也就是共用的意思,这样理解还是有些抽象,为此,咱们来理解下复用在通信领域的使用,在通信领域中为了充分利用网络连接的物理介质,往往在同一条网络链路上采用时分复用或频分复用的技术使其在同一链路上传输多路信号,到这里我们就基本上理解了复用的含义,即公用某个“介质”来尽可能多的做同一类(性质)的事,那IO复用的“介质”是什么呢?为此我们首先来看看服务器编程的模型,客户端发来的请求服务端会产生一个进程来对其进行服务,每当来一个客户请求就产生一个进程来服务,然而进程不可能无限制的产生,因此为了解决大量客户端访问的问题,引入了IO复用技术,即:一个进程可以同时对多个客户请求进行服务。也就是说IO复用的“介质”是进程(准确的说复用的是select和poll,因为进程也是靠调用select和poll来实现的),复用一个进程(select和poll)来对多个IO进行服务,虽然客户端发来的IO是并发的但是IO所需的读写数据多数情况下是没有准备好的,因此就可以利用一个函数(select和poll)来监听IO所需的这些数据的状态,一旦IO有数据可以进行读写了,进程就来对这样的IO进行服务。

  

理解完IO复用后,我们在来看下实现IO复用中的三个API(select、poll和epoll)的区别和联系

select,poll,epoll都是IO多路复用的机制,I/O多路复用就是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知应用程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。三者的原型如下所示:

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);



 1.select的第一个参数nfds为fdset集合中最大描述符值加1,fdset是一个位数组,其大小限制为__FD_SETSIZE(1024),位数组的每一位代表其对应的描述符是否需要被检查。第二三四参数表示需要关注读、写、错误事件的文件描述符位数组,这些参数既是输入参数也是输出参数,可能会被内核修改用于标示哪些描述符上发生了关注的事件,所以每次调用select前都需要重新初始化fdset。timeout参数为超时时间,该结构会被内核修改,其值为超时剩余的时间。

 select的调用步骤如下:

(1)使用copy_from_user从用户空间拷贝fdset到内核空间

(2)注册回调函数__pollwait

(3)遍历所有fd,调用其对应的poll方法(对于socket,这个poll方法是sock_poll,sock_poll根据情况会调用到tcp_poll,udp_poll或者datagram_poll)

(4)以tcp_poll为例,其核心实现就是__pollwait,也就是上面注册的回调函数。

(5)__pollwait的主要工作就是把current(当前进程)挂到设备的等待队列中,不同的设备有不同的等待队列,对于tcp_poll 来说,其等待队列是sk->sk_sleep(注意把进程挂到等待队列中并不代表进程已经睡眠了)。在设备收到一条消息(网络设备)或填写完文件数 据(磁盘设备)后,会唤醒设备等待队列上睡眠的进程,这时current便被唤醒了。

(6)poll方法返回时会返回一个描述读写操作是否就绪的mask掩码,根据这个mask掩码给fd_set赋值。

(7)如果遍历完所有的fd,还没有返回一个可读写的mask掩码,则会调用schedule_timeout是调用select的进程(也就是 current)进入睡眠。当设备驱动发生自身资源可读写后,会唤醒其等待队列上睡眠的进程。如果超过一定的超时时间(schedule_timeout 指定),还是没人唤醒,则调用select的进程会重新被唤醒获得CPU,进而重新遍历fd,判断有没有就绪的fd。

(8)把fd_set从内核空间拷贝到用户空间。

总结下select的几大缺点:

(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大

(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大

(3)select支持的文件描述符数量太小了,默认是1024

 

2.  poll与select不同,通过一个pollfd数组向内核传递需要关注的事件,故没有描述符个数的限制,pollfd中的events字段和revents分别用于标示关注的事件和发生的事件,故pollfd数组只需要被初始化一次。

 poll的实现机制与select类似,其对应内核中的sys_poll,只不过poll向内核传递pollfd数组,然后对pollfd中的每个描述符进行poll,相比处理fdset来说,poll效率更高。poll返回后,需要对pollfd中的每个元素检查其revents值,来得指事件是否发生。

 

3.直到Linux2.6才出现了由内核直接支持的实现方法,那就是epoll,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。epoll可以同时支持水平触发和边缘触发(Edge Triggered,只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发),理论上边缘触发的性能要更高一些,但是代码实现相当复杂。epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了这些文件描述符在系统调用时复制的开销。另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。

 

epoll既然是对select和poll的改进,就应该能避免上述的三个缺点。那epoll都是怎么解决的呢?在此之前,我们先看一下epoll 和select和poll的调用接口上的不同,select和poll都只提供了一个函数——select或者poll函数。而epoll提供了三个函 数,epoll_create,epoll_ctl和epoll_wait,epoll_create是创建一个epoll句柄;epoll_ctl是注 册要监听的事件类型;epoll_wait则是等待事件的产生。

  对于第一个缺点,epoll的解决方案在epoll_ctl函数中。每次注册新的事件到epoll句柄中时(在epoll_ctl中指定 EPOLL_CTL_ADD),会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝 一次。

  对于第二个缺点,epoll的解决方案不像select或poll一样每次都把current轮流加入fd对应的设备等待队列中,而只在 epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调 函数,而这个回调函数会把就绪的fd加入一个就绪链表)。epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd(利用 schedule_timeout()实现睡一会,判断一会的效果,和select实现中的第7步是类似的)。

  对于第三个缺点,epoll没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子, 在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。

总结:

(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用 epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在 epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的 时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间,这就是回调机制带来的性能提升。

(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要 一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内 部定义的等待队列),这也能节省不少的开销。
###############
这三种IO多路复用模型在不同的平台有着不同的支持,而epoll在windows下就不支持,好在我们有selectors模块,帮我们默认选择当前平台下最合适的
##############

#服务端
from socket import *
import selectors

sel=selectors.DefaultSelector()
def accept(server_fileobj,mask):
    conn,addr=server_fileobj.accept()
    sel.register(conn,selectors.EVENT_READ,read)

def read(conn,mask):
    try:
        data=conn.recv(1024)
        if not data:
            print('closing',conn)
            sel.unregister(conn)
            conn.close()
            return
        conn.send(data.upper()+b'_SB')
    except Exception:
        print('closing', conn)
        sel.unregister(conn)
        conn.close()

server_fileobj=socket(AF_INET,SOCK_STREAM)
server_fileobj.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server_fileobj.bind(('127.0.0.1',8088))
server_fileobj.listen(5)
server_fileobj.setblocking(False) #设置socket的接口为非阻塞
sel.register(server_fileobj,selectors.EVENT_READ,accept) #相当于网select的读列表里append了一个文件句柄server_fileobj,并且绑定了一个回调函数accept

while True:
    events=sel.select() #检测所有的fileobj,是否有完成wait data的
    for sel_obj,mask in events:
        callback=sel_obj.data #callback=accpet
        callback(sel_obj.fileobj,mask) #accpet(server_fileobj,1)

#客户端
from socket import *
c=socket(AF_INET,SOCK_STREAM)
c.connect(('127.0.0.1',8088))

while True:
    msg=input('>>: ')
    if not msg:continue
    c.send(msg.encode('utf-8'))
    data=c.recv(1024)
    print(data.decode('utf-8'))

4. AIO – 异步I/O模型

发起请求立刻得到回复,不用挂起等待; 数据会由内核进程主动完成拷贝

'''
举个例子:还是买菜刀
现在是网上下单到商店(系统调用)
商店确认(返回)
商店去进货(io操作)
商店收到货把货发个卖家(从内核缓冲区拷贝到用户缓冲区)
买家收到货(指定信号)

整个过程无等待
异步io

AIO框架在windows下使用windows IOCP技术,在Linux下使用epoll多路复用IO技术模拟异步IO

市面上多数的高并发框架,都没有使用异步io而是用的io多路复用,因为io多路复用技术很成熟且稳定,并且在实际的使用过程中,异步io并没有比io多路复用性能提升很多,没有达到很明显的程度
并且,真正的AIO编码难度比io多路复用高很多
'''

 

5 select poll 和epoll

#  1 select poll 和epoll都是io多路复用技术
select, poll , epoN都是io多路复用的机制。I/O多路复用就是通过一种机 制个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select, poll , epoll本质上都是同步I/O ,因为他们都需要在读写事件就绪后自己负责进行读写, 也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异 步I/O的实现会负责把数据从内核拷贝到用户空间。

# 2 select
select函数监视的文件描述符分3类,分别是writefds、readfds、和 exceptfds。调用后select函数会阻塞,直到有描述副就绪(有数据可读、 可写、或者有except),或者超时(timeout指定等待时间,如果立即返回 设为null即可),函数返回。当select函数返回后,可以通过遍历fdset,来 找到就绪的描述符。
select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个 优点。select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024 ,可以通过修改宏定义甚至重新编译内核的 方式提升这一限制,但是这样也会造成效率的降低。
# 3 poll
不同于select使用三个位图来表示三个fdset的方式,poll使用一个 pollfd的指针实现。
pollfd结构包含了要监视的event和发生的event,不再使用select '参数-值'传递的方式。同时,pollfd并没有最大数量限制(但是数量过大后 性能也是会下降)。和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。
从上面看,select和poll都需要在返回后,通过遍历文件描述符来获取 已经就绪的socket。事实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降

# 4 epoll
epoll是在linux2.6内核中提出的,是之前的select和poll的增强版本。相对 于select和poll来说,epoll更加灵活,没有描述符限制。epoll使用一个文 件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。

# 5 更好的例子理解
老师检查同学作业,一班50个人,一个一个问,同学,作业写完了没?select,poll
老师检查同学作业,一班50个人,同学写完了主动举手告诉老师,老师去检查 epoll

# 6 总结
在并发高的情况下,连接活跃度不高,epoll比select好,网站http的请求,连了就断掉
并发性不高,同时连接很活跃,select比epoll好,websocket的连接,长连接,游戏开发

三 同步I/O与异步I/O

  • 同步I/O
    • 概念:导致请求进程阻塞的I/O操作,直到I/O操作任务完成
    • 类型:BIO、NIO、IO Multiplexing
  • 异步I/O
    • 概念:不导致进程阻塞的I/O操作
    • 类型:AIO

注意:

  • 同步I/O与异步I/O判断依据是,是否会导致用户进程阻塞
  • BIO中socket直接阻塞等待(用户进程主动等待,并在拷贝时也等待)
  • NIO中将数据从内核空间拷贝到用户空间时阻塞(用户进程主动询问,并在拷贝时等待)
  • IO Multiplexing中select等函数为阻塞、拷贝数据时也阻塞(用户进程主动等待,并在拷贝时也等待)
  • AIO中从始至终用户进程都没有阻塞(用户进程是被动的)

四 并发-并行-同步-异步-阻塞-非阻塞

# 1 并发
并发是指一个时间段内,有几个程序在同一个cpu上执行,但是同一时刻,只有一个程序在cpu上运行
跑步,鞋带开了,停下跑步,系鞋带
# 2 并行
指任意时刻点上,有多个程序同时运行在多个cpu上
跑步,边跑步边听音乐
# 3 同步:
指代码调用io操作时,必须等待io操作完成才返回的调用方式
# 4 异步
异步是指代码调用io操作时,不必等io操作完成就返回调用方式
# 6 阻塞
指调用函数时候,当前线程别挂起
# 6 非阻塞
指调用函数时候,当前线程不会被挂起,而是立即返回

# 区别:
同步和异步是消息通讯的机制
阻塞和非阻塞是函数调用机制

五 IO设计模式

 Reactor模式,基于同步I/O实现
- Proactor模式,基于异步I/O实现

Reactor模式通常采用IO多路复用机制进行具体实现

- kqueue、epoll、poll、select等机制

Proactor模式通常采用OS Asynchronous IO(AIO)的异步机制进行实现

- 前提是对应操作系统支持AIO,比如支持异步IO的linux(不太成熟)、具备IOCP的windows server(非常成熟)

Reactor模式和Proactor模式都是事件驱动,主要实现步骤:

  1. 事件注册:将事件与事件处理器进行分离。将事件注册到事件循环中,将事件处理器单独管理起来,记录其与事件的对应关系。
  2. 事件监听:启动事件循环,一旦事件已经就绪/完成,就立刻通知事件处理器
  3. 事件分发:当收到事件就绪/完成的信号,便立刻激活与之对应的事件处理器
  4. 事件处理:在进程/线程/协程中执行事件处理器

使用过程中,用户通常只负责定义事件和事件处理器并将其注册以及一开始的事件循环的启动,这个过程就会是以异步的形式执行任务。

Reactor模式

 

Proactor模式

 

对比分析

Reactor模型处理耗时长的操作会造成事件分发的阻塞,影响到后续事件的处理;

Proactor模型实现逻辑复杂;依赖操作系统对异步的支持,目前实现了纯异步操作的操作系统少,实现优秀的如windows IOCP,但由于其windows系统用于服务器的局限性,目前应用范围较小;而Unix/Linux系统对纯异步的支持有限,因而应用事件驱动的主流还是基于select/epoll等实现的reactor模式

Python中:如asyncio、gevent、tornado、twisted等异步模块都是依据事件驱动模型设计,更多的都是使用reactor模型,其中部分也支持proactor模式,当然需要根据当前运行的操作系统环境来进行手动配置

点云数据处理:体素滤波算法 体素滤波是一种简单而有效的点云数据处理方法,可用于去除离群点和平滑点云表面。体素滤波是一种常用的点云数据处理算法,用于去除离群点并平滑点云表面。在本文中,我们将介绍CloudCompare和PCL(Point Cloud Library)中的体素滤波算法,并提供相应的源代码示例。PCL是一个专门用于点云处理的开源库,提供了一系列高效的点云处理算法和工具。然后,我们创建了一个。方法执行体素滤波,并将滤波后的点云保存为"filtered_cloud.ply"文件。方法来执行体素滤波,指定体素大小为0.01。 阅读详情

相关推荐

五种网络IO模型

  本文重点在于介绍五种网络IO模型  网络IO,会涉及到两个系统对象,一个是用户空间调用IO的进程或线程,另一个是内核空间的内核系统,比如发生IO操作read时,它会经历两个阶段。  因为在以上两个阶段上各有不同的情况,所以出现了多种网络 IO 模型。  本专栏知识点是通过零声教育的线上课学习,进行梳理总结写下文章,对c/c++linux课程感兴趣的读者,可以点击链接 C/C++后台高级服务器课程介绍 详细查看课程的服务。  .........

清风 6355

联想ThinkServer SR588 重装raid5阵列信息(装完centos7后,找不到硬盘)

这里写自定义目录标题找不到硬盘选择光盘启动 找不到硬盘 装完centos7之后,提示重启,重启之后,就一直无法启动。 进入bios 看了,确实是有设置硬盘为第一启动选项。 选择光盘启动 本地标准硬盘也是找不到。 1、 重启进入bios在系统手设置里找到存储信息, 然后找到如图选项回车进入。 选择主目录进入。 进入Configuration Management 里面 先清除原来的设置信息 选择已启用在yes 提示清除成功。 返回上一目录选择,选择 Create Virtual Drive 再选择S

熠铭心时空的博客 2万+

五大网络IO模型

nput/utput),即,通常指在(内部和外部)或其他周边设备之间的输入和输出,是信息处理系统(例如)与外部世界(可能是人类或另一信息处理系统)之间的通信。。该术语也可以用作行动的一部分;到“执行I/O”是执行输入或输出的操作。输入/出设备是硬件中由人(或其他系统)使用与电脑进行通信的部件。例如,键盘或鼠标是电脑的输入设备,而监控器和打印机是输出设备。电脑之间的通信设备(如电信调制解调器和网卡)通常执行输入和输出操作。将设备指定为输入或输出取决于视角。

qq13321123的博客 2936

从零开始:手把手教你做转录组与代谢组的联合分析(含R代码)

本文详细介绍了转录组与代谢组联合分析的全流程,包括数据准备、预处理、差异分析及可视化方法,并提供了实用的R代码示例。通过多组学整合分析,研究者可以更全面地理解生物过程,适用于疾病机制和药物开发等医学研究领域。

weixin_29306317的博客 439

基于python+flask框架的基于微信小程序的CR公司建设项目信息管理系统-前台(开题+程序+论文) 计算机毕设

特别是随着移动互联网技术的普及,企业对便捷、高效的信息管理系统的需求日益迫切。另一方面,该系统集成了仓管、物料、财务、人事、供应商等多个模块,实现了数据的集中管理和信息共享,有助于企业实现精细化管理,降低运营成本,提升决策效率。:深入调研CR公司的业务需求,明确系统应具备的功能模块,包括仓管员管理模块(物料信息、退回记录、申请信息、仓库信息管理)、财务员管理模块(资金信息管理、采购与租赁款项处理)、人事管理模块、供应商管理模块、项目管理模块(项目信息、设备采购、物料采购、设备租赁)、以及考勤打卡模块等。

zhihao503的博客 960

【网络编程下】五种网络IO模型

本篇文章主要从网络IO角度讲解IO模型,着重讲解多路复用在网络编程上的的应用。

Atcxr的博客 3084

Selenium ChromeDriver反爬与性能优化实战指南

ChromeDriver作为Selenium的核心驱动,本质是浏览器自动化执行引擎,其默认行为会暴露大量JS运行时指纹(如navigator.webdriver、window.chrome),极易被前端反爬系统识别;同时因进程管理粗放、渲染等待机制僵化,导致内存泄漏、僵尸进程和高并发下稳定性崩塌。本文围绕真实生产场景,系统解析浏览器指纹伪造原理、进程级资源管控策略、基于页面状态的智能等待范式,并提供Docker容器化、K8s弹性扩缩与Prometheus可观测性落地路径,助力开发者将ChromeDriver

weixin_29762151的博客 1259

网络模型——四种常见网络IO模型

文章目录1.IO读写原理1.1 内核缓冲区和进程缓存区1.1.1 用户进程和操作系统1.1.2 缓冲区的目的1.2 Java读写IO底层流程2.四种主要的IO模型2.1 基本概念2.1.1 阻塞与非阻塞2.1.2 同步与异步2.1.3 四种IO模型2.2 同步阻塞IO(Blocking IO) 网络IO模型一共介绍以下四种: 同步阻塞IO、同步非阻塞IO、IO多路复用和异步IO。 1.IO读写原理 文件的读写还是socket读写,在Java应用层开发,都是input或者output处理 用户程序进行IO操

weixin_45075135的博客 5480

RT-DETR-R18 的轻量化 Trick:剪枝与量化在模型中的应用

RT-DETR-R18轻量化技术通过结构化剪枝、混合精度量化和知识蒸馏的组合优化,实现了显著模型压缩效果。摘要如下: RT-DETR-R18模型通过创新轻量化技术组合,在保持46.2% mAP精度的前提下,将模型大小压缩至2.1MB(压缩率78%),计算量降至3.2 GFLOPs(减少78.2%),实现移动端28ms实时推理(加速37.8%)。核心技术包括:1)渐进式结构化剪枝系统,通过L1范数重要性评估和动态剪枝调度;2)混合精度量化策略,对关键层保留FP16精度;3)教师-学生知识蒸馏框架保持模型表达能

走向CTO的路上... 1194

手把手教你学simulink(26.8)--控制算法场景示例:基于强化学习的无人机姿态稳定控制系统

首先,我们需要定义无人机的姿态稳定控制环境。环境包括无人机的状态(姿态角、角速度等)和动作(电机转速)。我们还需要定义奖励函数,用于评估控制器的表现。matlab深色版本% 定义环境% 定义状态空间% 12个状态变量% 定义动作空间% 电机转速范围奖励函数用于评估控制器的表现。我们可以根据无人机的姿态误差、角速度误差以及控制输入的变化率来设计奖励函数。具体来说,当无人机的姿态接近设定值时,给予正奖励;当姿态误差较大或控制输入变化剧烈时,给予负奖励。matlab深色版本。

MHD0815的博客 496

网络io模型

所谓的I/O就是计算机内存与外部设备之间拷贝数据的过程。我们知道CPU访问内存的速度远远高于外部设备,因此CPU是先把外部设备的数据读到内存里,然后再进行处理。请考虑一下这个场景,当你的程序通过 CPU向外部设备发出一个读指令时,数据从外部设备拷贝到内存往往需要一段时间,这个时候CPU没事干 了,你的程序是主动把CPU让给别人?还是让CPU不停地查:数据到了吗、数据到了吗…这就是I/O模型要解决的问题。

sinat_34814635的博客 980

如何在 UniApp 中接入讯飞语音听写功能 文末附vue3+vue2完整代码

在开发过程中,我遇到了讯飞接口返回空数据的问题。通过仔细检查传送的每一帧数据,我发现问题出在第一帧的配置信息以及 Base64 数据的切片。确保每一帧的数据正确且符合接口要求,问题就能够得到解决。希望这个过程能帮助你在项目中顺利对接讯飞语音识别。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1000

【Linux网络】五种IO模型详解

通过这篇文章,你会了解五种IO模型,明白多路复用中的select的用法

odoaobo的博客 1291

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【LInux网络】五种IO模型与高级IO概念 及 非阻塞IO详解

本篇博文对【LInux网络】五种IO模型与高级IO概念 及 非阻塞IO详解做了一个较为详细的介绍,不知道对你有没有帮助呢觉得博主写得还不错的三连支持下吧!会继续努力的~

2301_77954967的博客 1217

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

linux 网络io命令详解,Linux下五种网络IO模型详解

本文我们主要来了解一下Unix/Linux下5种网络IO模型:blocking IO, nonblocking IO, IO multiplexing, signal driven IO, asynchronous IO的基本原理,更好的理解在高级语言中的异步编程,一起来看看吧,希望对大家学习linux有所帮助。写在前面为了更好的理解下面提到的Linux下5种网络IO的概念,我们还是有必要先理清几...

weixin_29351351的博客 411

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

【网络编程】十四、五种常见IO模型详解

文章主要介绍了五种常见的IO模型,并通过钓鱼的例子形象地解释了这些模型的工作原理。五种IO模型分别是:阻塞式IO、非阻塞式IO、信号驱动式IO、多路转接式IO和异步IO。其中,前四种属于同步IO,进程或线程亲自参与IO处理;而异步IO则由操作系统处理完成后通知应用程序。文章还强调了IO的本质是“等待+数据拷贝”,提高IO效率的关键在于减少等待时间。此外,文章还介绍了高级IO中的重要概念,如同步与异步、阻塞与非阻塞的区别,并提到了一些高级IO技术,如非阻塞IO、多路转接等。最后,文章介绍了fcntl函数,用于

lirendada的博客 1228

linux网络io模型详解,这样讲解Linux的五种io模型,应该通俗易懂

原标题:这样讲解Linux的五种io模型,应该通俗易懂关注 来源 | Linux研习社如若转载请联系原公众号今天分享Linux系统的io模型。Linux总共有5种io模型,分别是:blocking IO 阻塞IO模型On Blocking IO 非阻塞IO模型IO multiplexing 多路复用IO模型singnal dirven 信号驱动IO模型asyn 异步IO模型我们首先来了解一下几个基...

weixin_29266749的博客 332

Linux—五种IO模型与非阻塞IO

本文系统介绍了五种I/O操作模型及其实现原理。核心观点是:I/O操作分为等待数据就绪和数据拷贝两个阶段,不同模型的关键差异在于第一阶段如何处理。五种模型分别为:1)阻塞I/O:进程全程挂起等待;2)非阻塞I/O:轮询检查状态;3)信号驱动I/O:内核通过信号通知;4)I/O多路复用:单线程监控多连接;5)异步I/O:内核完成全部操作后通知。文章还辨析了同步/异步、阻塞/非阻塞的概念差异,并通过fcntl函数示例展示了非阻塞I/O的实现方法。最后指出,I/O多路复用凭借高效的单线程多连接管理能力,成为高并发网

我的博客 684

网络IO模型和JAVA中的NIO

IO指的就是数据的输入与输出,包括网络IO、磁盘IO。只要是IO,它都会被划分为2个阶段,分别是数据的准备阶段和数据的传输阶段。前者指的是硬件资源(如网卡、磁盘)和内存缓冲区的数据传递,后者指的是缓冲区和用户程序之间的数据传递。

zjoh33的博客 272

聊聊Netty那些事儿之从内核角度看IO模型

当我们熟悉了select的原理后,就很容易理解内核给我们提供的select API了。从select API中我们可以看到,select系统调用是在规定的超时时间内,监听(轮询)用户感兴趣的文件描述符集合上的可读可写异常三类事件。select传递给内核监听的文件描述符集合中数值最大的文件描述符+1,目的是用于限定内核遍历范围。select监听的文件描述符集合为,那么maxfdp1的值为5。对可读事件感兴趣的文件描述符集合。对可写事件感兴趣的文件描述符集合。对可写事件感兴趣的文件描述符集合。这里的。

fuladulu的博客 426

网络部分常见问题

UDP协议具有无连接、不可靠、面向数据报的特点,而TCP是面相连接、可靠传输、面向字节流的。三次握手的目的是为了确认双方的接收和发送能力是否正常,第一次握手验证了客户端的发送和服务端的接收正常,第二次握手验证了服务端的发送正常,但站在服务端的角度看并不确定客户端是否收到了SYN+ACK报文,因此并不能确认客户端的接收是否正常。,此时B以为是A发送的新的请求连接,于是发出确认字符,如果没有三次握手,该连接建立,但是A并没有发出请求连接,所以B就会一直等待A发送确认字符,这样B等了很久,白白浪费B的资源。

a3094472656的博客 906

Linux下五种网络IO模型

本文我们主要来了解一下Unix/Linux下5种网络IO模型:blocking IO, nonblocking IO, IO multiplexing, signal driven IO, asynchronous IO的基本原理,更好的理解在高级语言中的异步编程,一起来看看吧,希望对大家学习linux有所帮助。   写在前面   为了更好的理解下面提到的Linux下5种网络IO的概念,...

yangrendong的专栏 2338

从 BIO 到 AIO 全链路拆解:Reactor 模型演进与高并发 IO 架构落地实战

本文深入解析Java高并发IO模型演进与Reactor架构,从BIO、NIO到AIO的技术发展路径。首先介绍UNIX五种IO模型标准,详细对比同步/异步、阻塞/非阻塞的核心差异。重点剖析NIO的三大组件(Channel、Buffer、Selector)实现原理,并通过完整代码示例展示BIO/NIO/AIO的服务端与客户端实现。系统讲解Reactor模型的三个阶段演进:单线程→单Reactor多线程→主从Reactor多线程,结合Netty框架展示工业级实现方案。最后提供线程模型优化、TCP参数调优等最佳实践

果酱 の 博客 654

5种网络IO模型(有图,很清楚)

本文转自https://www.cnblogs.com/findumars/p/6361627.html 5种网络IO模型(有图,很清楚) 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出的答案都可能不同,比如wiki,...

bangduji5725的博客 178
上一篇: Linux内核之进程管理《Linux内核设计与实现》
下一篇: Redis不是一直号称单线程效率也很高吗,为什么又采用多线程了?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值