首页 > 编程语言 >编程深水区之并发①:什么是并发编程

编程深水区之并发①:什么是并发编程

时间:2024-08-06 19:54:06浏览次数:9  
标签:协程 深水 单线程 编程 并发 线程 进程 多线程

并发编程是一种让程序能够执行多个任务的编程技术,多个任务的执行时间有重合,如交替执行、同时执行等。相对于传统的从上到下依次同步执行代码,我们也称并发编程为异步编程。目前,常见的并发模型主要有两种,一是多线程模型,二是单线程事件循环模型

一、多线程模型

1、进程和线程

了解线程之前,需要知道进程和线程的区别。Windows和Linux的进程和线程表现略有差异,以下对比仅针对Windows操作系统。

  • 进程指操作系统中程序的一次执行过程,拥有独立的内存、文件等资源。一个应用可以有多个进程。
  • 线程指进程中的执行单元,线程共享进程的全局变量和资源,但有独立的堆栈和上下文
  • 进程是线程的容器,线程共享进程的资源
  • 进程有入口线程,一个进程可以创建更多线程
  • 进程和线程的图示:

image.pngimage.png

2、多线程模型之操作系统线程

目前多线程的实现方式,主要有两种,一是操作系统线程,二是用户态协程。
操作系统线程由操作系统进行管理,每个线程有独立的堆栈和上下文,但共享进程的全局变量和资源。操作系统线程在内核态调度,可以充分利用多核CPU等硬件资源,从而提高系统的整体性能,特别适合CPU密集型操作和长期运行的任务;同时,线程间共享全局变量,操作更加简便,且不存在消息通讯的开销。它主要存在以下几个问题:一是线程占用内存资源比较大;二是线程切换的性能开销比较大;三是共享资源的争抢和死锁问题。
由于传统多线程的弊病,现代框架大多引入了async/await模式,实现线程的池化管理。线程被框架提前创建,并托管在后台管理的线程池中,由后台自动管理线程的创建和销毁、动态调整线程数量,从而实现线程的高效复用。比如C#的Web框架 - AspNetCore,使用async/await后,处理高并发的性能,在很多测试中,并不比Go这类实现协程的框架差。
本系列后面的章节,我们将以C#和AspNetCore为例,展开叙述操作系统线程。

3、多线程模型之用户态协程

协程由程序语言或运行时进行管理,是比线程更轻量级的并发单位,特别适合高并发的场景。协程的创建和切换,只需要在用户态完成,避免了进入内核态的开销,降低了上下文切换的成本,开销更低;同时,协程不需要分配大量的内核资源,通常一个协程只需要几KB内存,占用内存少,可以创建更加的协程。协程的主要问题,是不同协程之间的消息通讯,操作比较复杂,通讯开销也比较大。
协程的具体实现方式,又分“有栈”和“无栈”。比如Go语言提供了goroutine,实现了有栈协程,虽然每个协程有独立的栈空间,但仍然支持同时运行成千上万个goroutine,它鼓励使用“消息传递”方式来完成不同协程之间的通信和同步,通过使用channel可以安全的在多个goroutine之间传递数据。而Swift语言则提供了Task,表示一个独立的并发执行单元,实现了无栈协程,更加轻量,但不同协程之间的通信,必须通过Actor来实现。而仓颉语言则实现了M:N线程模型,M个用户态协程在N个操作系统线程上执行,本质上还是一种用户态协程。
本系列后面的章节,我们将以仓颉为例,展开叙述用户态协程。

二、单线程事件循环模型

1、事件循环机制

JS是为Web而生的,Web有个特点,就是IO密集型,请求数据>浏览器渲染DOM,任务非常简单。大多数情况下,单线程是足够了,但Web请求有个异步等待的问题,容易造成同步代码的阻塞。所以,JS诞生时就有了事件循环机制,但一开始是很简陋的,主要通过使用回调函数和setTimeout来实现,后来逐渐有了任务对列、Promise、async/await,事件循环机制才逐步完善。

2、Chrome浏览器

传统浏览器有一个很严重的问题,就是一旦代码出现长时阻塞或异常,整个浏览器就崩了。所以Chrome带来了多进程,子进程托管在主进程下面,每个浏览器Tab,都是一个子进程,即使崩了,也不会影响其它Tab和主进程,而且Tab之间的资源独立,也更加安全。Chrome不仅解决了浏览器“爱崩迪”的问题,还带来了新一代的JS执行引擎-V8。听名字,就很NB的感觉。确实,V8一出,一统江湖。

3、Node.js

传统后端存在线程切换的问题,在处理IO密集型这类高并发任务时,表现并不理想,而这类异步任务就特别适合用单线程事件循环机制来处理,所以有人将V8引擎带到了后端,并创造出了Node.js。
Node.js不但能够利用单线程事件循环机制,处理高并发的IO密集型任务,而且也能使用子进程,处理一些CPU密集型的计算任务。但是,子进程毕竟不是多线程,它有两个问题:一是子进程虽然托管在主进程下面,但它本质还是进程,占用独立的内存和文件资源,所以创建和销毁的开销远高于线程;二是进程之间,需要通过消息机制进行通讯,通讯开销也比较大,尤其是子进程之间的沟通,还需要借助主进程桥接。
本系列后面的章节,我们将以JS和Node.js为例,展开叙述单线程事件循环机制以及Node.js的子进程。


*这是一个系列文章,将全面介绍多线程、用户态协程和单线程事件循环机制,建议收藏、点赞哦!
*你在并发编程过程中碰到了哪些难题?欢迎评论区交流~~~


我是functionMC > function MyClass(){…}
C#/TS/鸿蒙/AI/中美科技竞争等问题,以及如何写Bug、防脱发、送外卖等问题,都可以私信提问哦!

编程深水区.png

标签:协程,深水,单线程,编程,并发,线程,进程,多线程
From: https://blog.csdn.net/2401_85195613/article/details/140929371

相关文章

  • 编程深水区之并发④:Web多线程
    Node的灵感来源于Chrome,更是移植了V8引擎。在Node中能够实现的多线程,在Web环境中自然也可以。一、浏览器是多进程和多线程的复杂应用在本系列的第二章节,有提到现代浏览器是一个多进程和多线程的复杂应用。浏览器主进程统管全局,每个Tab页都会创建一个渲染子进程,同时还有G......
  • 【编程语言】Delphi使用教程
    目录一、概述二、Delphi的开发环境三、Delphi基本功能3.1创建新项目3.2设计表单3.3编写代码3.4编译和运行3.5调试四、Delphi的高级的概念和技巧4.1使用组件和类4.2数据库操作4.3图形和多媒体4.4网络编程4.5调试和优化4.6 部署和分发4.7版本控制和......
  • Java基础编程练习题50题(没更新完会持续更新)
    1.古典问题有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?publicclassRabbit{publicstaticvoidmain(String[]args){intmonths=12;//假设计算12个月的情......
  • Java编程练习之集合
    1.产生10个1-100的随机数,并放到一个数组中,把数组中大于等于10的数字放到一个list集合中,并打印到控制台。publicstaticvoidmain(String[]args){//生成随机数Randomr=newRandom();//创建数组int[]arr=newint[10];/......
  • 异步编程和多线程有
    在C#中,多线程和异步编程是两个相关但不完全相同的概念。下面我会解释这两个概念的区别,并给出一些常见的问题及解答。多线程vs异步编程多线程:多线程指的是在一个进程中创建多个线程来并行执行任务。多线程可以用来处理计算密集型任务,充分利用多核处理器的计算能力。多......
  • Python:学生成绩管理系统(大学编程期末实验)
    引言在这个信息时代,教育管理的自动化已成为提高效率的关键。本文将介绍如何使用Python开发一个学生成绩管理系统,旨在简化成绩记录、查询和分析的过程。创作灵感来源本项目灵感来源于我在教育机构的工作经历,以及对提高教育管理效率的持续追求。通过复盘过往项目,我意识到一个......
  • 探索编程世界:大学新生的最佳入门路径与学习方法
    编程已成为当代大学生的重要技能,不仅为计算机科学专业的学生提供了核心竞争力,也为其他领域的学生打开了通往创新和创造的门。面对多种多样的编程语言和学习资源,许多新生常常感到迷茫:应该选择哪种编程语言?如何制定有效的学习计划?如何避免常见的学习陷阱?本文将为大学新生提供......
  • Apache Flink开发时选择Java还是Scala作为编程语言
    在ApacheFlink的开发过程中,选择Java还是Scala作为编程语言是一个重要的决策点。这两种语言各有其独特的优势和特点,适合不同的开发场景和需求。以下是对这一选择的详细探讨,旨在帮助开发者更好地理解并做出合理的选择。一、ApacheFlink简介ApacheFlink是一个开源的分布式......
  • C++11革新之旅:探索C++编程的无限可能
    C++11革新之旅:探索C++编程的无限可能C++11,作为C++语言的一个重要标准,为C++编程带来了革命性的变革。它不仅引入了众多新特性和改进,还极大地增强了C++的表达能力、提高了程序的性能和资源利用率。本文将从多个方面深入探讨C++11的新特性,并解析这些特性如何改变C++编程的方式......
  • 高级的shell编程
    高级的Shell编程通常涉及一些复杂的技术和技巧,用于解决更复杂的问题或优化Shell脚本的性能和可维护性。以下是一些高级Shell编程的主题和技术:1.函数编程:   使用函数将Shell脚本模块化和组织化。   编写递归函数解决问题,如目录遍历或树状结构处理。2.错误处理和......