Java教程

实验总结分析报告:从系统的角度分析影响程序执行性能的因素

本文主要是介绍实验总结分析报告:从系统的角度分析影响程序执行性能的因素,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

实验总结分析报告:从系统的角度分析影响程序执行性能的因素

要求

一、 精简的Linux系统概念模型

Linux系统一般有4个主要部分:内核、shell、文件系统和应用程序。内核、shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序、管理文件并使用系统。

img

二、I/O多路复用之select系统调用验证模型

select调用介绍

I/O多路复用模型允许我们同时等待多个套接字描述符是否就绪。Linux系统为实现I/O多路复用提供的最常见的一个函数是select函数,该函数允许进程指示内核等待多个事件中的任何一个发生,并只有在一个或多个事件发生或经历一段指定的时间后才唤醒它。

select模型如下图所示,用户首先将需要进行IO操作的socket添加到select中,然后阻塞等待select系统调用返回。当数据到达时,socket被激活,select函数返回。用户线程正式发起read请求,读取数据并继续执行。从流程上来看,使用select函数进行IO请求和同步阻塞模型没有太大的区别,甚至还多了添加监视socket,以及调用select函数的额外操作,效率更差。但是,使用select以后最大的优势是用户可以在一个线程内同时处理多个socket的IO请求。用户可以注册多个socket,然后不断地调用select读取被激活的socket,即可达到在同一个线程内同时处理多个IO请求的目的。而在同步阻塞模型中,必须通过多线程的方式才能达到这个目的。

图片描述

select系统调用验证模型

应用程序层面

在服务器端,服务器通过调用socket()函数创建一个socket对象,通过bind()方法绑定一个端口号与IP,在调用listen()方法完成初始化后,调用accept()阻塞等待,处于监听端口的状态,客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服务器应答,服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK段,服务器收到后从accept()返回。

socket连接成功之后,用户首先将需要进行IO操作的socket添加到select中,然后阻塞等待select系统调用返回。当数据到达时,socket被激活,select函数返回。用户线程正式发起read请求,读取数据并继续执行。

 

文件系统层面

socket()函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。当我们调用socket()创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数,否则就当调用connect()listen()时系统会自动随机分配一个端口。

 

shell层面

select是一个复杂的函数,有许多不同的应用场景,我们将只讨论第一种场景:等待一组描述符准备好读。

select函数的参数有多个。其中,参数n指定需要测试的描述符的数目,测试的描述符范围从0到n-1。第二个参数fdset指定需要测试的可读描述符集合。当fdset集合中有描述符可读,或者经历了timeout时间时,select将返回。当select返回时,作为一个副作用,select修改了参数fdset指向的描述符集合,这时fdset变成由读集合中准备好可以读了的描述符组成。select函数的返回值则指明了就绪集合的基数。值得注意的是,由于这个副作用,我们必须每次在调用select时都更新读集合。

#include <unistd.h>
#include <sys/types.h>
​
int select(int n, fd_set *fdset, NULL, NULL, struct timeval *timeout);
​
FD_ZERO(fd_set *fdset);          // 将fdset初始为为空集合
FD_CLR(int fd, fd_set *fdset);   // 从fdset清除fd
FD_SET(int fd, fd_set *fdset);   // 将fd添加到fdset
FD_ISSET(int fd, fd_set *fdset); // fd是否存在于fdset 

 

内核层面

通过调用select()函数,在用户空间中保存了已连接的 Socket 文件描述符数组的fds,会被映射到一个set结构的bitmapbitmap的每一位对应fds的下标,表示需要监听的socket),select()函数将bitmap结构拷贝到内核空间中,让内核去监听网络事件是否发生,我们调用select可以告知内核我们对哪些描述符感兴趣以及等待多久时间。

在内核层面中,内核就是让CPU就是不停遍历检测bitmap中每一位对应的文件描述符,检查这个文件描述符是否有IO网络事件的发生。如果是,则接收数据。如果接收的数据长度为0,或者发生WSAECONNRESET错误,则表示客户端套接字主动关闭,这时需要将服务器中对应的套接字所绑定的资源释放掉,然后调整我们的套接字数组(将数组中最后一个套接字挪到当前的位置上),关系到套接字列表的操作都需要使用循环,在轮询的时候,需要遍历一次,再新的一轮开始时,将列表加入队列又需要遍历一次.也就是说,Select在工作一次时,需要至少遍历2次列表,这是它效率较低的原因之一。

图片描述

三、影响应用程序性能的因素分析

select调用的性能影响因素主要在于:

1.每次调用时要重复地从用户态读入参数。

2.每次调用时要重复地扫描文件描述符。由上面对select()函数的分析可知,select()函数主要的工作在于内核中不停遍历检测bitmap中每一位对应的文件描述符,检查这个文件描述符是否有IO网络事件的发生。

3.每次在调用开始时,要把当前进程放入各个文件描述符的等待队列。在调用结束后,又把进程从各个等待队列中删除。

4.select调用中使用到的bitmap结构为1024位,最多只能监听1024个文件描述符(监听1024个socket)

 

 

这篇关于实验总结分析报告:从系统的角度分析影响程序执行性能的因素的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!