进程、线程、协程、并发、并行、IO多路复用

目录

一、什么是IO操作

二、进程、线程、协程

1、进程是资源分配的基本单位

2、线程是任务调度的基本单位

3、协程—由线程创建并全权负责的小弟

三、并行、并发及其与CPU内核数的关系

1、理解并行与并发的区别

2、进程、线程与CPU核数之间的关系

3、同一个进程里的线程可以并行执行吗(满足条件时可以)

四、IO多路复用

五、参考文(zi)献(liao)


我竟然妄想在小小的篇幅下把这四件事讲明白,离谱,但又不太离谱~

在多线程、多进程、并行、并发这几个概念中,有很多知识点容易让人第一次看完后还是模棱两可的,这里主要是对概念细节的记录,因为我原来学的时候多少也是似懂非懂的,最近又系统地过了一遍,发现了原来很多认知上的小误解,在这里统一做下梳理与记录。 

一、什么是IO操作

IOInput 与 Output 首字母的组合,就是表示对数据的输入输出操作。

第一次接触 IO 是学习单片机的时候,把单片机的引脚叫做 IO 口,单片机的 IO 口操作就是对高低电平的读写操作,但本质上还是对字节流的读写。网络编程中的IO其实也是一样的,都是对字节流的读写操作:读写文件是IO操作、socket/TCP/UDP这些都是IO操作,只要有数据交换的地方都有IO操作。

二、进程、线程、协程

三者间的关系:没有线程的进程是没有灵魂的,协程是线程养的一帮小弟,完全由线程统一调控。

1、进程资源分配的基本单位

何谓资源分配?资源分配就是系统分配给这个进程的内存空间、CPU、磁盘IO等等。进程本身不能执行任何任务。可以这么理解:进程只是为线程抢了一块肥沃的土地,并配备了一系列齐全的农具,除此之外基本啥也不干了,而对这块地什么时候种什么植物的操作(CPU任务调度)就需要进程通过创建线程来执行了。

2、线程任务调度的基本单位

何谓任务调度?任务调度就是CPU执行具体的任务(一般是调用函数)。线程是由进程创建的,一个进程至少有一个线程,没有线程的进程就是 si 的,啥也干不了!所以说线程是进程的灵魂,同时,只要有线程存在,其就必须依附于一个进程上,也就是说没有肉体依附的灵魂卵用没有~

对于打开一个APP来说,这个APP就是一个进程,而在这个APP上播放音乐、即时聊天等就是由这个进程创建的一个个线程实现的。

3、协程—由线程创建并全权负责的小弟

协程是由线程创建的执行体,可以理解为线程创建的“小线程”。协程的切换同样需要现场保护、恢复现场等操作,但协程比线程更轻量,由于不需要操作系统交互,其切换开销要比线程切换开销小;而线程的切换除了寄存器上下文的切换,还需要进行优先级、内核态进出等等更多与操作系统间的交互。

用户程序不能操作内核空间,只能给协程分配用户栈,而操作系统对协程一无所知,所以协程又被称为用户态线程。

协程多用于IO多路复用的场景。

三、并行、并发及其与CPU内核数的关系

多线程、高并发,对于初学者来说确实是云里雾里的。多线程就一定是并行执行的吗?并行和并发有什么区别?为什么是高并发,咋不叫高并行呢?并行执行的条件是啥呢?这些都是需要搞明白的。

1、理解并行与并发的区别

并发使用了CPU时间片轮转机制,并不是真正的同时执行,只是轮转很快让人感觉是在“同时执行”所以才叫“并发”。并行才是真正的同时执行。

2、进程、线程与CPU核数之间的关系

拥有2个运算设备的CPU称作双核CPU,拥有4个运算器的CPU称作4核CPU,以此类推。也就是说,一个CPU中可能包含多个运算设备(核)。核的个数与可同时运行的线程数(并行)相同。相反,若线程数超过核数,线程将分时使用CPU资源(并发)。但因为CPU运转速度极快,我们会感到所有进程同时运行。当然,核数越多这种感觉越明显。

3、同一个进程里的线程可以并行执行吗(满足条件时可以)

当系统有一个以上核心时,则同一个进程里的两个线程的操作有可能并行执行。当一个核心执行一个线程时,另一个核心可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行。

这里得再明确一个问题:进程只管资源分配,线程才是任务调度的基本单位,因此最终程序的执行,无论是并行还是并发都是体现在线程上的!CPU看到的也只是线程!

但是说进程可以并行执行也没问题,因为有进程存在就一定会有线程存在,如果两个进程里面的线程是并行执行的话就越等于这两个进程在并行执行了。但是你得清楚,实际在运行的是线程。

总结就是:

单核CPU,线程只能并发执行;多核CPU,线程和进程以及同一个进程中的线程都可以并行执行,当线程或进程数量多余核心数时,一般是并行并发同时存在的

但是在 Python 中,无论是单核还是多核,一个进程同时只能由一个线程在执行。其根源是 GIL 的存在。GIL 的全称是 Global Interpreter Lock(全局解释器锁),来源是 Python 设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到 GIL,并且在一个 Python 进程中,GIL 只有一个。拿不到GIL的线程,就不允许进入 CPU 执行。因此python中想要实现并行执行,只能用多进程实现。

对于计算复杂型的运算(如矩阵运算),我们要尽可能多地让代码并行执行.对于IO密集型的操作,尽可能多地使用并发,提高CPU的使用率,从而提高CPU的运行效率 

  • 创建和销毁较频繁使用线程,因为创建进程花销大。
  • 需要大量数据传送使用线程,因为多线程切换速度快,不需要跨越进程边界。
  • 安全稳定选进程;快速频繁选线程。

四、IO多路复用

(建议搭配结尾的视频食用,以下内容多少借鉴了这些链接中的视频)

socket 接受客户端连接,并返回给应用程序一个文件描述符fd,每个文件描述符就是一个数,代表文件描述符的编号,用于识别不用的socket(返回给应用程序的只有一个socket描述符)。每个TCP在操作时操作系统都会为其在内核空间分配一个读缓冲区和一个写缓冲区,要获得相应数据就要从都缓冲区拷贝到用户空间中,同样的要通过socket发送数据,也要先把数据拷贝到写缓冲区才行。

(图片来源: 【协程第二话】协程和IO多路复用更配哦~_哔哩哔哩_bilibili

对于大量IO请求有以下几种处理方式:

  • 阻塞等待+多线程/多进程:需要开辟线程浪费资源

阻塞式IO(没有数据来时就让出CPU)在高并发情况下会增加调度开销。

  • 非阻塞+忙轮询:占用CPU(while和for),CPU利用率不高

非阻塞式IO(不让出CPU)用忙轮询方式,挨个尝试访问,但是需要频繁检查SOCKET是否就绪,很难把握轮询的间隔时间,容易造成空耗CPU,加剧响应延迟。

  • 多路IO复用

IO多路复用,由操作系统提供支持,把需要等待的socket加入到监听集合,这样就可以通过一次系统调用同时监听多个socket,有socket就绪了就可以逐个处理了,既不用为等待某个socket而阻塞,也不会陷入忙等待之中。

Linux实现了三种IO复用实现方式:select / poll / epoll,这属于拓展内容了,有兴趣可以查看后面的链接。

五、参考文(zi)献(liao)

进程、线程、并行、并发参考资料:

一个视频告诉你“并发、并行、异步、同步”的区别_哔哩哔哩_bilibili

cpu的核数和进程_多线程,多进程,多核总结_玉漏迟的博客-CSDN博客

多CPU,多核,多进程,多线程 - 苏铭枫 - 博客园 (cnblogs.com)

进程、线程和CPU 之间的关系(一)_nandao158的博客-CSDN博客_线程和cpu

协程:

【协程第一话】协程到底是怎样的存在?_哔哩哔哩_bilibili

IO多路复用参考资料:

深入理解Linux中网络I/O复用并发模型_哔哩哔哩_bilibili

【协程第二话】协程和IO多路复用更配哦~_哔哩哔哩_bilibili

【并发】IO多路复用select/poll/epoll介绍_哔哩哔哩_bilibili

协程与IO多路复用

协程和IO多路复用_稚与的博客-CSDN博客_协程在io多路复用中的应用

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Java的虚拟线程是指在Java程序中使用的线程,它是运行在操作系统的内核线程之上的一层抽象。虚拟线程主要用于线程调度和线程池实现,可以有效地管理系统资源并避免线程频繁创建和销毁带来的开销。 IO复用是指程序可以同时监听多个网络套接字的输入输出事件,当某个事件发生时能够及时地做出响应。它可以使用多个线程或者单个线程实现,可以大大提升程序的吞吐量和效率。 ### 回答2: Java的虚拟线程是指在Java中使用的一种线程模型,称为"弹性线程池"。传统的线程模型中,每个线程都需要占用一个操作系统的线程资源,当需要创建大量的线程时,会耗费大量的内存和线程切换开销。而虚拟线程可以通过使用少量的线程,动态地处理多个任务。虚拟线程采用了程的概念,可以在一个线程中动态开启和暂停多个任务,从而提高了并发性能。 而IO复用是一种IO模型,可以在一个线程中同时监听多个IO事件。在传统的阻塞IO模型中,每个客户端连接都需要一个线程来处理,当连接数增加时,线程数量也会相应增加,导致系统资源浪费。而IO复用通过一个线程管理多个IO事件,并且只在有事件发生时才会进行处理,大大提高了系统的并发能力。 Java中的IO复用主要通过选择器(Selector)来实现,它可以监控多个通道的IO事件,并在事件发生时通知线程进行处理。在利用选择器进行IO复用时,可以使用非阻塞IO来处理连接,即一个线程可以同时处理多个连接,提高了系统的吞吐量和响应速度。 虚拟线程和IO复用在Java中都是为了提高系统的并发性能和资源利用率。虚拟线程通过动态的任务调度和程的概念,实现了在少量线程上同时执行多个任务的能力。IO复用则通过一个线程同时监听多个IO事件的方式,减少了线程切换和系统资源的开销。这两个技术的结合可以进一步提高Java程序的并发处理能力,并优化系统的性能表现。 ### 回答3: Java的虚拟线程是指Java虚拟机(JVM)在操作系统的线程之上提供的一种更高级别的并发性抽象。它将操作系统线程映射到Java线程,并通过使用线程池技术来管理线程的生命周期。虚拟线程可以更有效地使用操作系统线程资源,减少线程的创建和销毁开销,并提供更高的并发性能。它还提供了一些高级并发特性,例如线程池的线程重用、线程的优先级管理和线程间的作等。通过使用虚拟线程,开发人员可以更方便地编写高并发的Java程序,同时充分利用操作系统的硬件并发性。 IO复用是一种利用操作系统提供的非阻塞IO机制来同时监听多个IO通道的技术。它通过将多个IO通道注册到一个选择器对象(Selector)上,并在有IO事件发生时,使用单个线程来处理所有已注册的IO通道。这种方式可以大大减少线程的创建和销毁开销。在Java中,通过使用NIO(New IO)的特性,可以方便地实现IO复用。Java中的Selector类提供了对多复用的支持,可以同时监听多个通道的IO事件,并通过“就绪集合”来获取已发生的事件。开发人员可以使用Selector来监测多个通道的IO状态,并根据不同的事件类型来执行相应的处理逻辑。 总之,Java的虚拟线程和IO复用都是为了提高Java程序的并发性能和资源利用效率。虚拟线程将操作系统线程映射到Java线程,并提供更高级别的并发性抽象,可以更高效地管理线程资源。而IO复用则利用非阻塞IO和选择器来同时监听多个IO通道的IO事件,减少线程开销,提高IO处理性能。这些技术在Java程序中的应用可以帮助开发人员更好地处理高并发和大量IO操作的场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

地球被支点撬走啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值