您好!欢迎来到爱源码

爱源码

热门搜索: 抖音快手短视频下载   

说说Golang goroutine和发生了什么。 {源码交易}

  • 时间:2022-07-12 00:09 编辑: 来源: 阅读:268
  • 扫一扫,手机访问
摘要:说说Golang goroutine和发生了什么。 {源码交易}
今天,我们来盘点一下在戈朗发生了什么。 Golang,Golang,Golang真的很浪。今天,我们来盘点一下Golang并发的那些事,具体来说就是goroutine。先把他们放一放(主要是我现在不擅长,不敢出来瞎折腾)。 先不说golang的功过。 反正所有大佬都在说我只是个吃瓜的,偶尔打酱油逃避~ 说到并发,一系列概念就出来了。为了照顾好自己,顺便复习一下基本概念process(英文:process)的定义,指的是已经在电脑中运行的程序。 进程曾经是分时系统的基本操作单元。 在面向进程的系统中(如早期的UNIX、Linux 2.4及更早的版本),进程是程序的基本执行实体。在面向线程的系统中(如大多数操作系统,Linux` 2.6及其升级版本),进程本身不是基本的运行单元,而是线程的容器。 程序本身只是对指令、数据及其组织形式的描述,相当于一个名词。进程是程序(那些指令和数据)真正运行的实例,可以想象成现在进行时。 几个流程可能与同一个程序相关,每个流程可以同步或异步独立运行。 现代计算机系统可以在同一时间段内将多个程序以进程的形式加载到内存中,通过分时(或时分复用),体现在一个求解器上并行运行的感觉。 同样,使用多线程技术的操作系统或计算机架构(多线程是指每个线程代表一个进程中独立的执行上下文),同一程序的并行线程可以同时运行在多个CPU主机或网络上(在不同的CPU上)。 操作系统需要一种方法来创建进程。 以下四个主要事件将创建一个进程:系统初始化(简单称为关机后启动)。正在运行的程序执行创建过程的系统调用(比如朋友发来一个网站,你点击后打开浏览器进入网页)。客户请求创建新流程(例如,打开程序、打开QQ、微信)。创建后,批处理作业初始化过程的终止过程开始运行并解决相关任务。 但不会永远,最终还是要完成或者退出。 然后会发生以下四种情况:进程终止,正常退出(自愿),错误退出(自愿),崩溃退出(非自愿),被别人杀死(非自愿),正常退出:你退出浏览器,你点击它,你误退出:此时你正兴致勃勃的看电视剧,突然程序内部发生bug,导致退出崩溃退出:你的程序崩溃,被别人杀死:比如在windows上,用任务管理器关闭进程,前两种状态在逻辑上是相似的:运行状态(实际占用CPU)就绪状态(正在运行,但其他进程正在运行并被挂起)阻塞状态(除非某个外部时间发生,否则进程无法运行)。 这两种状态的进程都可以运行,但是第二种状态暂时没有分配CPU,一旦分配给CPU就可以运行了。第三种状态与前两种不同,这种状态下的进程无法运行,即使CPU空闲。 有兴趣的话可以进一步了解一下进程的实现,多进程设计模型,进程池技术的应用,至少由以下两部分组成:资源进程提前创建的空闲进程,管理进程会将工作分配给空闲进程来解决。 进程管理进程负责创建资源进程,将工作移交给空闲的资源进程,回收已经完成工作的资源进程。 资源过程和管理过程的概念很好理解。管理进程如何有效地管理资源进程,给资源进程分配任务,回收闲置的资源进程?如果管理进程想要有效地管理资源进程,那么管理进程和资源进程必须通过IPC、信号、信号量、消息队列、管道等进行交互。 进程池(Process pool):准确地说,它实际上并不存在于我们的操作系统中,而是IPC、信号、信号量、消息队列、管道等。管理多个流程,以减少不断的打开和关闭操作。 为了减少不必要的资源损失,线程定义线程(英文:thread)是操作系统可以调度操作的最小单位。 大多数情况下,它包含在流程中,是流程中的实际操作单元。 线程是指流程中控制流的单个序列。多个线程可以在一个进程中并发,每个线程并行执行不同的任务。 在Unix System V和SunOS中,也称为轻量级进程,但轻量级进程更多指内核线程,用户线程称为线程。 线程是独立调度和分派的基本单位。 可以为操作系统的内核调度线程。同一个进程中的多个线程会在进程中共享相同的系统资源,比如虚拟地址空间、文件描述符、信号解析等等。 但是,同一进程中的多个线程有自己的调用堆栈、自己的寄存器上下文和自己的线程本地存储。 一个进程可以由多个线程来解决,每个线程并行执行不同的任务。 如果进程有很多任务要完成,需要很多线程,调用很多核,那么在多核或者多CPU上使用多线程编程,或者CPU支持超线程的优势是很明显的,就是提高了程序的吞吐量。 想象一下人们是如何工作的。核心是人。人越多,同时能解决的事情就越多,而线程就是手。人手越多,工作效率越高。 在单CPU单核计算机上,利用多线程技术,还可以将进程中负责I/O求解和人机交互的部分和经常被阻塞的密集型计算部分分开,编写专门的workhorse线程来执行密集型计算。多任务虽然不如多核,但它有多线程的能力,从而提高了程序的执行效率。 线程池线程池(英文:Thread pool):一种线程使用模式 线程太多会带来调度开销,影响缓存局部性和整体性能。 线程池维护多个线程,等待管理程序分配可以并发执行的任务。 这避免了在解决短期任务时创建和销毁线程的开销。 线程池既能保证内核的充分利用,又能防止过度调度。 可用线程的数量应取决于可用并发解析器、解析器内核、内存、网络套接字等的数量。 比如线程数一般是+2,线程太多会导致额外的线程切换开销。 调度任务来执行线程的一种常见方法是使用同步队列,称为任务队列。 池中的线程等待队列中的任务,并将完成的任务放入完成队列中。 线程池模式一般分为两种:HS/HA半同步/半异步模式和L/F主从模式。 半同步/半异步模式,也称为生产者-消费者模式,是一种常见且简单的实现模式。 它分为三层:同步层、队列层和异步层。 同步层主线程求解工作任务并存储在工作队列中,工作线程从工作队列中取出任务进行求解。如果工作队列为空,则无法获得任务的工作线程将被挂起。 因为线程之间有数据通信,所以不适合数据交换量大的场合。 在Leader-follower模式下,线程池中的线程可以处于三种状态之一:Leader、follower或worker处理器。 在任何时候,线程池中只有一个主线程。 当事件到达时,leader线程负责消息分离,选择其中一个追随者作为后继领导者,然后将自己设置为worker来处理事件。 解决方案完成后,工作线程将自己的状态设置为从线程。 这种模式实现起来比较复杂,但是避免了线程之间交换任务数据,提高了CPU缓存的相似性。 Ace(自适应通信环境)提供了领导者-追随者模式的实现。 线程池的可伸缩性对性能有很大的影响。 创建太多线程会浪费某些资源,有些线程没有得到充分利用。 销毁太多线程会导致浪费时间,以后再创建它们。 创建线程太慢会导致等待时间长和性能差。 销毁线程太慢,导致其他线程饥饿。 教练,英文叫协程,也叫微线程和纤程。教练是客户端状态中的一种轻量级线程。 协同进程有自己的寄存器上下文和堆栈。 协调调度切换时,寄存器上下文和堆栈保存到其他地方,切换回来时,恢复之前保存的寄存器上下文和堆栈。 因此,协同进程可以保持最后一次调用的状态,即所有本地状态的特定组合。进程每重新进入一次,就相当于进入了上次调用的状态。 协同过程本质上是一个单一过程。与多进程相比,协同进程不需要线程上下文切换、原子操作锁定和同步的开销,其编程模型非常简单。 多个串行任务,之后执行另一个任务。 比如饭后散步(先坐下吃饭,吃完饭再散步)并行执行多项任务,交替进行。比如做饭,一会儿洗菜,一会儿吸收(菜脏了,洗干净写下来,骄傲~),开始一起吃饭,看电视。阻塞和非阻塞阻塞阻塞阻塞状态是指当所需的计算资源不可用时,程序被挂起的状态。 在等待一个操作完成时,当一个程序不能继续自己解决其他事情时,它就被称为阻塞。 常见的阻塞形式有:网络I/O阻塞、磁盘I/O阻塞、客户输入阻塞等。 阻塞是无处不在的,包括CPU切换上下文的时候,所有进程都不能真正解决事情,都会被阻塞。 如果是多核CPU,则不能利用正在执行上下文切换操作的核。 当一个非阻塞程序在等待一个操作时,就说它没有被阻塞,可以继续解决其他的事情。 非阻塞在任何程序级别和任何情况下都不可能存在。 只有当程序封装的级别可以包含独立的子程序单元时,它才可能具有非阻塞状态。 非阻塞的存在是因为阻塞的存在,也正是因为一个操作阻塞造成的耗时低效,我们才不得不把它做成非阻塞的。 为了完成某项任务,同步和异步同步中的不同程序单元在执行过程中需要通过某种通信来协调。我们称这些程序单元为同步执行。 比如在一个购物系统中升级商品库存时,需要使用“线锁”作为通信信号,这样不同的升级请求就被强制按顺序排队,然后升级库存的操作就同步了。 简而言之,同步意味着有序。 为了异步地完成一项任务,不同的程序单元可以不通过通信和协调来完成任务,不相关的程序单元可以异步。 比如爬虫下载网页。 调度器调用下载器后,可以调度其他任务,而不需要与下载器保持通信来协调行为。 不同网页的下载、保存等操作互不相关,不需要相互通知和协调。 这些异步操作的完成时间是不确定的。 以上对异步和异步的理解之后,就是进程、线程等等一系列的东西,真的很难受。 但我相信你已经有了一个初步的概率,所以在这里我们会对异步和异步有更深的理解。 在此之前,我们先总结一下。其实以上各种进化路线,无非就是一句话,提高效率。 (废话~)那么,提高效率有两个因素:增加输入增加输出,尽可能避免不必要的损失(比如减少上下文切换等。) 如何区分是异步代码还是非异步代码?其实很简单,就是能否独立完成不需要我们参与的部分。 我们从结果中逆向思考,例如,我们发送一个网络请求,其间有网络I/O阻塞,然后我们挂起它进行测试,并做其他事情。等他反应过来,我们就在这个阶段做下一步操作。 那么这就是异步的。另外,写作业和上厕所。这个时候我正在做作业。突然,我想去洗手间。我们走吧。 上完厕所,回来继续写作业。在我上厕所的这段时间里,我的作业不会有什么进展,所以我们可以理解为这是一个非异步的goroutine,终于到了干真家伙的时候了。废话不多。 如何实现?只需要定义很多任务,让系统帮我们把这些任务分配给CPU,实现并发执行。 Go语言中的Goroutine就是这样一种机制。goroutine的概念类似于thread,但是goroutine是由Go的运行时来调度和管理的。 Go程序会智能地将goroutine中的任务恰当地分配给各个CPU。 Go之所以被称为现代编程语言,是因为它在语言层面内置了调度和上下文切换机制。 在Go编程中,你不需要编写自己的进程、线程和协程。你的技能包里只有一个技能——戈鲁丁。当你需要一个任务并发执行的时候,你只需要把任务打包成一个函数就可以了。只要打开一个goroutine就可以执行这个功能。线程增长的goroutine和OS线程(操作系统线程)通常有固定的堆栈内存(一般2MB)。goroutine的堆栈在其生命周期开始时只是一个小堆栈(通常为2KB)。goroutine的堆栈不是固定的,可以根据需要增减。goroutine的堆栈大小限制可以达到1GB,尽管很少使用这么大。 因此,用Go语言一次创建大约100,000个goroutine也是可能的。 Goroutine模型GPM是go语言运行时级别的实现,是go语言本身实现的一套调度系统。 不同于操作系统调度OS线程 g很好理解,它是一个goroutine,除了这个goroutine的信息之外,还包含了与P的绑定等信息。 p管理一组goroutine队列,队列中会存储当前运行的goroutine的上下文(函数指针、堆栈地址和地址边界)。p将调度少量由其自己管理的goroutine队列(例如,挂起占用较长CPU时间的goroutine,运行后续的goroutine等。).当它自己的队列被消耗时,它将被从全局队列中取出。如果全局队列也被消耗,它将从其他P的队列中抓取任务。 m `(机器)`是Go运行时对操作系统内核线程的虚拟化。M和内核线程一般是一一映射的,一个groutine最后放到M上执行;p和m一般一一对应。 它们的关系是:P管理一组运行在m上的G挂载。 当一个G在一个M上被长时间阻塞时,运行时会创建一个新的M,被阻塞的G所在的P会把剩下的G挂载到新的M上。 当旧的G块完成或者接收方认为它死了时,回收旧的M。 p的数量由运行时设置。GOMAXPROCS(最大值为256),它默认为Go1.5版之后的物理线程数 并发大的时候会加少量的P和M,但不会太多。如果切换过于频繁,就得不偿失了。 从单线程调度的角度来看,Go语言相对于其他语言的优势在于OS线程由OS内核调度,而GoRoutines由GO runtime自己的调度器调度,调度器使用了一种叫做m:n调度(将M个GORoutines复用/调度到N个OS线程)的技术 它的一个特点是goroutine的调度是在客户端状态下完成的,不涉及内核状态和客户端状态的频繁切换,包括内存的分配和释放。它在客户端状态下维护一个很大的内存池,不直接调用系统的malloc函数(除非内存池需要改变),所以成本远低于调度OS线程。 另一方面充分利用多核的硬件资源,在物理线程上近似划分几个go routine,加上自身go routine的超轻量,都保证了go调度的性能。 GoMAXPROCSGo运行时的调度程序使用GoMAXPROCS参数来确定同时执行GO代码需要多少个OS线程。 是计算机上默认的CPU核心数。 例如,在一个8核机器上,调度器将同时将Go代码调度到8个OS线程(GOMAXPROCS在m:n调度中是N) Go语言可以通过运行时设置当前程序并发时所占用的CPU逻辑核的数量。GOMAXPROCS()函数。 在Go1.5版本之前,默认使用单核执行。 在版本Go1.5之后,默认情况下使用相同数量的CPU逻辑核心。 创建goroutine使用goroutine非常简单。通过在调用函数时在函数名前面添加go关键字,可以为函数创建goroutine。 一个goroutine必须对应一个功能,当然也可以创建多个go routine来执行同一个功能。 语法如下:如果你现在跃跃欲试,我只想对你说:“少侠,请稍等~”。我还没说完我的句子。 我只说了如何创建goroutine,没说这是怎么用的。 嘻嘻~首先我们来看看没有使用Goloutine的代码。输入结果如下。然后,让我们使用Goloutine并如下运行示例代码:输出如下。乍一看,我家小子的速度提高了几乎不是一个数量级。秒~仔细看会发现7和9去哪了?走了,盯着~答案在下篇揭晓~期待下篇,盘点Golang的并发事件,goroutine的并发控制得心应手。本文参考华为云社区《数一数Golang并发的那些事件》,参考作者为PayneWu。


  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【域名/主机/服务器|】qq邮箱提醒在哪里打开(2024-06-04 18:58)
【技术支持|常见问题】1556原创ng8文章搜索页面不齐(2024-05-01 14:43)
【技术支持|常见问题】1502企业站群-多域名跳转-多模板切换(2024-04-09 12:19)
【技术支持|常见问题】1126完美滑屏版视频只能显示10个(2024-03-29 13:37)
【技术支持|常见问题】响应式自适应代码(2024-03-24 14:23)
【技术支持|常见问题】1126完美滑屏版百度未授权使用地图api怎么办(2024-03-15 07:21)
【技术支持|常见问题】如何集成阿里通信短信接口(2024-02-19 21:48)
【技术支持|常见问题】算命网微信支付宝产品名称年份在哪修改?风水姻缘合婚配对_公司起名占卜八字算命算财运查吉凶源码(2024-01-07 12:27)
【域名/主机/服务器|】帝国CMS安装(2023-08-20 11:31)
【技术支持|常见问题】通过HTTPs测试Mozilla DNS {免费源码}(2022-11-04 10:37)

联系我们
Q Q:375457086
Q Q:526665408
电话:0755-84666665
微信:15999668636
联系客服
企业客服1 企业客服2 联系客服
86-755-84666665
手机版
手机版
扫一扫进手机版
返回顶部