并发模型——前置知识

本文探讨了系统调用在并发编程中的作用,涉及IO多路复用(select, poll, epoll)、非阻塞IO(NIO)和异步IO(AIO),以及如何选择合适的线程数以优化CPU密集型和I/O密集型任务。理解这些概念有助于提高程序性能和资源利用率。
摘要由CSDN通过智能技术生成


一、系统调用

  1. 解释下系统调用:系统调用,就是操作系统内核提供给用户进程的接口。
  2. 系统调用的目的:一些敏感的操作,让内核去完成,比如IO操作。用户进程是没有权限去执行的。操作系统内核具有最高的权限,可以使用计算机的所有资源。用户进程想要执行敏感操作,需要借助内核去完成。
  3. 用户态和内核态概念:多数计算机有两种运行状态,用户态和内核态。
    操作系统内核运行在内核态,而其他进程运行在用户态。内核态模式下,操作系统具有对于硬件的完全访问权限。用户态进程想要执行敏感操作时,可通过系统调用,陷入到内核态,即将数据传入内核态,让内核去执行,然后内核将执行结果在返回给用户进程。
  4. 为什么说并发会谈到系统调用呢?因为从用户态陷入到内核态会导致数据的拷贝,我们设计一个高并发的程序,就也应该把这些因素考虑在内。
  5. 你能解释下:观看主播时,你听到主播的声音,经历了多少次数据的拷贝吗?首先音频数据包被你的电脑的网卡接收,然后将数据拷贝到内核中,再从内核中拷贝到tcp缓冲区中,在从tcp缓冲区中拷贝到应用程序中,假设应用程序里没有发生数据拷贝,应用程序解析完还要拷贝到内核中,然后内核在拷贝给声卡。

二、高级IO

1.IO多路复用

IO多路复用可以监听多个文件描述符,先构造一张我们感兴趣的文件描述符表,然后调用一个函数(select、poll、epoll)直到文件描述符表中至少有一个准备好进行IO时,该函数才返回。

select、poll、epoll都实现了IO多路复用,之所以有这三个鬼,是因为他们的出现时间是又先后顺序的。

这篇文章解释的很生动,易懂,强推!!。IO 多路复用是什么意思? - 罗志宇的回答 - 知乎
https://www.zhihu.com/question/32163005/answer/55772739

  1. select
    缺点:
    1.数据拷贝开销大,每次select的执行,用户进程和内核都会改变文件描述符表,然后拷贝给对方。
    2.可以监听的文件描述符的数量有限,1024个。
    3.当内核监听到有文件描述符可以进行IO了,她不会直接告诉用户进程是哪个文件描述符,需要用户进程自己去遍历。几十几百个连接还好,几十万的连接遍历起来,那真是酸爽的不要不要的。。。。
  2. poll
    poll解决了select文件描述符数量的限制,但他还是需要遍历,时间复杂度很高。而且每次调用都要进行内核和用户进程间的数据的拷贝。
  3. epoll
    epoll是基于poll的改进。
    优点:
    1.首先采用mmap,将用户进程的一段内存映射到内核的一段内存上,从而避免了数据的拷贝操作。
    2 .当有文件描述符可以进行IO时,他会直接告诉进程是哪个文件描述符,在也不需要遍历了。。
    3 .epoll的设计采用红黑树,红黑树很高效这是毋庸置疑的吧,所以epoll也高效,这么解释没问题吧,哈哈

2.非阻塞IO(NIO)

非阻塞IO可以实现一个线程同时处理多个sock连接,首先他read下sock1,有数据直接读出来,没有数据直接返回,然后read下sock2,有数据直接读出来,没有数据直接返回,以此类推。所以,不难想到,非阻塞IO应该与轮询机制一起使用。很多时候其实都没有数据到达,服务器却一直在轮询,这太浪费cpu资源了。

3.异步IO(AIO)

利用异步IO技术,进程告诉内核:当文件描述符read好可以进行IO时,用一个信号通知它。
缺点:
1.信号的数量有限,远远小于可用的文件描述符的数量,所以没法用一个信号对应一个文件描述符,还得遍历,看哪个文件描述符能进行IO操作。
2.可移植性差,一些系统提供的异步IO接口不一致

三、并发和并行

1.并发是指一段时间内处理多个事件。
2.并行是指同一时刻处理多个事件。
问题:应用程序设置多少个线程合适啊?
我们在进行并发设计的时候,要充分利用并行的特性。并行是依靠物理层的处理器。如果线程数量过多,就会造成一个处理器上频繁的线程切换,处理速度反而变慢了。如果线程数量太少,我们就没能充分的发挥出多处理器的性能。

CPU密集型计算任务:IO操作少,大部分操作都需要利用cpu的任务。
I/O密集型计算任务:IO操作多的任务。

由于在IO的时候,线程不占用cpu资源,可让出cpu,让其他线程工作。

线程多少合适?
对于CPU密集型计算任务,线程数 = CPU核心数 + 1;
对于I/O密集型计算任务,线程数 = 2 * CPU核心数;
对于普通任务,线程数 = N(CPU核心数) * (1 + WT(线程等待时间) / ST(线程时间运行时间))。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值