当前位置: Linux > 关于io模型

关于io模型

2021-03-19 分类:Linux 作者:admin 阅读(21)

进程开销太大,线程则轻量级的多,所以我们还可以通过在进程中创建新的线程来处理请求。

上面基于进程或线程的模型还是有问题,因为每新进来一个 TCP 连接请求,就需要分配一个进程或线程,从而引发著名的 C10K 问题(一台机器要维护 1 万个连接,就要创建 1 万个进程或者线程,操作系统是无法承受的。如果维持 1 亿用户在线需要 10 万台服务器,成本也太高了),为此,又诞生了一种新的技术 —— 多路 IO 复用。

默认情况下,一个线程的栈要预留1M的内存空间,而一个进程中可用的内存空间只有2G,所以理论上一个进程中最多可以开2048个线程,但是内存当然不可能完全拿来作线程的栈,所以实际数目要比这个值要小。

所谓多路 IO 复用可以简单理解为一个线程维护多个 Socket(前面多进程或多线程都是一个进程或线程维护一个 Socket),这也有两种实现方式:轮询和事件通知。

因为 Socket 在 Linux 系统中以文件描述符形式存在,所以我们把一个线程维护的所有 Socket 叫做文件描述符集合,所谓轮询就是调用内核的 select 函数监听文件描述符集合是否有变化,一旦有变化,就会依次查看每个文件描述符,对那些发生变化的文件描述符进行读写操作,然后再调用 select 函数监听下一轮的变化。

显然,轮询的效率有点低,因为每次文件描述符集合有变化,都要将全部 Socket 轮询一遍,这大大影响了系统能够支撑的最大连接数。如果改成事件通知的方式,情况要好很多。所谓事件通知,就是某个文件描述符发生变化,调用 epoll 函数主动通知。这种方式使得监听的 Socket 数据增加的时候,效率不会大幅度降低,能够同时监听的 Socket 的数目也非常多。上限就为系统定义的、进程打开的最大文件描述符个数。

同步异步和多路单路是两组正交的概念。不存在“多路复用是否异步”这样的概念问题,只能在某一个特定实现上讨论这一点。一般而言只是异步单路和同步多路实现起来比较困难或者没什么必要罢了,并不是说这样的设计不存在。

然后,同步异步和多路单路在软件上都是管理模式的区别,所以你显然可以实现在同步IO上的异步机制,只要你去进行资源管理就行了。具体方法就得具体问题具体讨论了。


同步与异步

  • 同步: 同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回。在IO编程一节中,我们已经知道,CPU的速度远远快于磁盘、网络等IO。在一个线程中,CPU执行代码的速度极快,然而,一旦遇到IO操作,如读写文件、发送网络数据时,就需要等待IO操作完成,才能继续进行下一步操作。这种情况称为同步IO。多线程和多进程的模型虽然解决了并发问题,但是系统不能无上限地增加线程。由于系统切换线程的开销也很大,所以,一旦线程数量过多,CPU的时间就花在线程切换上了,真正运行代码的时间就少了,结果导致性能严重下降。另一种解决IO问题的方法是异步IO。当代码需要执行一个耗时的IO操作时,它只发出IO指令,并不等待IO结果,然后就去执行其他代码了。一段时间后,当IO返回结果时,再通知CPU进行处理。
  • 异步: 异步就是发起一个调用后,立刻得到被调用者的回应表示已接收到请求,但是被调用者并没有返回结果,此时我们可以处理其他的请求,被调用者通常依靠事件,回调等机制来通知调用者其返回结果。

同步和异步的区别最大在于异步的话调用者不需要等待处理结果,被调用者会通过回调等机制来通知调用者其返回结果。

阻塞和非阻塞

  • 阻塞: 阻塞就是发起一个请求,调用者一直等待请求结果返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。
  • 非阻塞: 非阻塞就是发起一个请求,调用者不用一直等着结果返回,可以先去干其他事情。
  • 那么同步阻塞、同步非阻塞和异步非阻塞又代表什么意思呢?举个生活中简单的例子,你妈妈让你烧水,小时候你比较笨啊,在哪里傻等着水开(同步阻塞)。等你稍微再长大一点,你知道每次烧水的空隙可以去干点其他事,然后只需要时不时来看看水开了没有(同步非阻塞)。后来,你们家用上了水开了会发出声音的壶,这样你就只需要听到响声后就知道水开了,在这期间你可以随便干自己的事情。(异步非阻塞)。

  • BIO (Blocking I/O)

  • 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。
  • NIO (New I/O)

  • NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。
  • AIO (Asynchronous I/O)

  • AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。(除了 AIO 其他的 IO 类型都是同步的,这一点可以从底层IO线程模型解释,推荐一篇文章:《漫话:如何给女朋友解释什么是Linux的五种IO模型?》 )查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。
  • 参考资料:https://blog.csdn.net/m0_38109046/article/details/89449305
  • https://laravelacademy.org/post/21096

进程:进程是能拥有资源和独立运行的最小单位,也是程序执行的最小单位。任务调度采用的是时间片轮转的抢占式调度方式,而进程是任务调度的最小单位,每个进程有各自独立的一块内存,使得各个进程之间内存地址相互隔离。

线程:线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。一个标准的线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成。而进程由内存空间(代码、数据、进程空间、打开的文件)和一个或多个线程组成。

协程:是一种基于线程之上,但又比线程更加轻量级的存在,这种由程序员自己写程序来管理的轻量级线程叫做『用户空间线程』,具有对内核来说不可见的特性。

多核(心)处理器是指在一个处理器上集成多个运算核心从而提高计算能力,也就是有多个真正并行计算的处理核心,每一个处理核心对应一个内核线程。

现在的电脑一般是双核四线程、四核八线程,是采用超线程技术将一个物理处理核心模拟成两个逻辑处理核心,对应两个内核线程,所以在操作系统中看到的CPU数量是实际物理CPU数量的两倍,如你的电脑是双核四线程,打开“任务管理器\性能”可以看到4个CPU的监视器,四核八线程可以看到8个CPU的监视器。

当线程的数量小于处理器的数量时,线程的并发是真正的并发,不同的线程运行在不同的处理器上。但当线程的数量大于处理器的数量时,线程的并发会受到一些阻碍,此时并不是真正的并发,因为此时至少有一个处理器会运行多个线程。

  1. 线程的切换由操作系统负责调度,协程由用户自己进行调度,因此减少了上下文切换,提高了效率。
  2. 线程的默认Stack大小是1M,而协程更轻量,接近1K。因此可以在相同的内存中开启更多的协程。

    协程的目的

    在传统的J2EE系统中都是基于每个请求占用一个线程去完成完整的业务逻辑(包括事务)。所以系统的吞吐能力取决于每个线程的操作耗时。如果遇到很耗时的I/O行为,则整个系统的吞吐立刻下降,因为这个时候线程一直处于阻塞状态,如果线程很多的时候,会存在很多线程处于空闲状态(等待该线程执行完才能执行),造成了资源应用不彻底。

    最常见的例子就是JDBC(它是同步阻塞的),这也是为什么很多人都说数据库是瓶颈的原因。这里的耗时其实是让CPU一直在等待I/O返回说白了线程根本没有利用CPU去做运算,而是处于空转状态。而另外过多的线程,也会带来更多的ContextSwitch开销。

    对于上述问题,现阶段行业里的比较流行的解决方案之一就是单线程加上异步回调。其代表派是node.js以及Java里的新秀Vert.x。

    而协程的目的就是当出现长时间的I/O操作时,通过让出目前的协程调度,执行下一个任务的方式,来消除ContextSwitch上的开销。

     

    来源:https://studygolang.com/articles/23615?fr=sidebar

    原理图:https://www.zhihu.com/question/50185085/answer/183463734

       推荐阅读:https://www.liaoxuefeng.com/wiki/1016959663602400/1017959540289152

「三年博客,如果觉得我的文章对您有用,请帮助本站成长」

赞(0) 打赏

支付宝
微信
0

支付宝
微信
标签:

上一篇:

下一篇:

你可能感兴趣

共有 0 - 关于io模型

博客简介

精彩评论

  • admin(6年前 (2020-03-09))

    分别用不同厚度的筏板定义,画图后这设置筏板变截面处理。 http://f.fwxgx.co...

    评:新文章!
  • admin(6年前 (2020-03-09))

    分别用不同厚度的筏板定义,画图后这设置筏板变截面处理。 http://f.fwxgx.co...

    评:新文章!
  • admin(6年前 (2020-03-09))

    新增一个框架图! http://biji.jinli.vip/wp-content/upl...

    评:新文章!
  • 一位WordPress评论者(6年前 (2020-02-13))

    嗨,这是一条评论。 要开始审核、编辑及删除评论,请访问仪表盘的“评论”页面。 评论者头像来自...

    评:世界,您好!