栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

Go并发编程——goroutine(上)

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Go并发编程——goroutine(上)

⼀、并发与并⾏ (⼀)、Go是并发语⾔,⽽不是并⾏语⾔
  1. 在讨论如何在Go中进⾏并发处理之前,我们⾸先必须了解什么是并发,以及它与并⾏性有什么不同。(Go is a concurrent language and not a parallel one. )
  2. 并发性Concurrency
  • 把任务在不同的时间点交给处理器进⾏处理。在同⼀个时间点,任务不会同时运⾏。
  • 并发性是同时处理许多事情的能⼒。
  • 举个例⼦,打电话和吃饭。吃饭时,电话来了,需要停⽌吃饭去接电话。电话接完后回来继续吃饭,这个过程是并发执⾏。
  1. 并⾏性parallelism
  • 并⾏是把⼀个任务分配给每⼀个处理器独⽴完成。在同⼀个时间点,任务⼀定是同时运⾏。
  • 并⾏就是同时做很多事情。这听起来可能与并发类似,但实际上是不同的。
  • ⽤同样打电话和吃饭的例⼦去理解。吃饭时,电话来了,边吃饭边接电话,这个过程是并⾏执⾏。这就是所谓的并⾏性(parallelism)。
  • Go在Gomaxprocs数量与任务数量相等时,可以做到并⾏执⾏,但是⼀般情况下都是并发执⾏。
  1. 并发性和并⾏性——⼀种技术上的观点。
  • 假设我们正在编写⼀个web浏览器。web浏览器有各种组件,其中两个是web⻚⾯呈现区域和从internet下载⽂件的下载器。
    • 当这个浏览器运⾏在单个核处理器中时,处理器将在浏览器的两个组件之间进⾏上下⽂切换。它可能会下载⼀个⽂件⼀段时间,然后它可能会切换到呈现⽤户请求的⽹⻚的html。这就是所谓的并发性。并发进程从不同的时间点开始,它们的执⾏周期重叠。在这种情况下,下载和呈现从不同的时间点开始,它们的执⾏重叠。
    • 假设同⼀浏览器运⾏在多核处理器上。在这种情况下,⽂件下载组件和HTML呈现组件可能同时在不同的内核中运⾏。这就是所谓的并⾏性。
    • 并⾏性Parallelism不会总是导致更快的执⾏时间。
      • 这是因为并⾏运⾏的组件可能需要相互通信。例如,在我们的浏览器中,当⽂件下载完成时,应该将其传递给⽤户,⽐如使⽤弹出窗⼝。这种通信发⽣在负责下载的组件和负责呈现⽤户界⾯的组件之间。当组件在多个内核中并⾏运⾏时,这种通信开销很⾼。因此,并⾏程序并不总是导致更快的执⾏时间!
      • 这种通信开销在并发concurrent 系统中很低。
  • 在单CPU上,是os代码强制把⼀个进程或者线程挂起,换成另外⼀个,所以实际上是并发的,只是“概念上的并⾏”。在现在的多核的cpu上,线程可能是“真正并⾏的”。
(⼆)、什么是并发?
  1. 并发指在同⼀时间内可以执⾏多个任务。
  • 并发编程含义⼴泛,可以是多线程编程,也可以是多进程编程,还可以是编写分布式程序。
  • 并发编程的思想来⾃于多任务操作系统,它允许同时运⾏多个程序。
  • 早期单⽤户操作系统,任务是⼀个接⼀个运⾏,单个任务的执⾏完全是串⾏的。只有在⼀个任务运⾏完成之后,另⼀个任务才会被读取。
  • 多任务操作系统则允许终端⽤户同时运⾏多个程序。当⼀个程序暂时不需要使⽤CPU的时候,系统会把该程序挂起或中断,以使其他程序可以使⽤CPU。
  • 最早⽀持并发编程的计算机编程语⾔是汇编语⾔。
  • 串⾏程序特指只能被顺序执⾏的指令列表,并发程序则是可以被并发执⾏的多个串⾏程序的综合体。因此并发程序内部会被划分为多个部分,每个部分都可以看做⼀个串⾏程序。
  • 串⾏程序中的所有代码的先后顺序都是固定的,⽽并发程序中只有部分代码是有序的。这⼀特性被称为不确定性。这导致并发程序每次运⾏的代码执⾏路径都是不同的,即便输⼊数据相同也会如此。
  1. Go语⾔通过编译器运⾏时runtime,从语⾔上⽀持并发的特性。
  2. Go语⾔的并发通过Goroutine特性完成。
⼆、进程和线程 (⼀)、基本概念
  1. 进程(process)和线程(thread)
  • 进程和线程是操作系统级别的两个基本概念。
  • 计算机的核⼼是CPU,它承担了所有的计算任务。它就像⼀座⼯⼚,时刻在运⾏。
  • 进程就好⽐⼯⼚的⻋间,它代表CPU所能处理的单个任务。进程是⼀个容器。
  • 线程就好⽐⻋间⾥的⼯⼈。⼀个进程可以包括多个线程。线程是容器中的⼯作单位。
  • ⼀个进程的内存空间是共享的,每个线程都可以使⽤这些共享内存。就如同⻋间的空间是⼯⼈们共享的,许多房间是每个⼯⼈都可以进出的。
  • ⻋间的每个房间⼤⼩不同,有些房间最多只能容纳⼀⼈,⽐如厕所。⾥⾯有⼈的时候,其他⼈就不能进去了。这代表⼀个线程使⽤某些共享内存时,其他线程必须等它结束,才能使⽤这⼀块内存。防⽌他⼈进⼊的简单⽅法,就是⻔⼝加⼀把锁。先到的⼈锁上⻔,后到的⼈看到上锁,就在⻔⼝排队,
    等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防⽌多个线程同时读写某⼀块内存区域。
  • 还有些房间,可以同时容纳n个⼈,⽐如厨房。如果⼈数⼤于n,多出来的⼈只能在外⾯等着。这好⽐某些内存区域,只能供给固定数⽬的线程使⽤。这时的解决⽅法,就是在⻔⼝挂n把钥匙。进去的⼈就取⼀把钥匙,出来时再把钥匙挂回原处。后到的⼈发现钥匙架空了,就知道必须在⻔⼝排队等着了。这种做法⽤来保证多个线程不会互相冲突。
  1. 进程的定义
  • 进程是程序的⼀次动态执⾏过程;
  • 进程需要经历从代码加载、代码执⾏到执⾏完毕的⼀个完整过程,这个过程也就是进程本身从产⽣、发展到消亡的过程;
  • 每个运⾏中的程序就是⼀个进程;
  • 进程是⼀个实体。每⼀个进程都有它⾃⼰的地址空间,⼀般情况下,包括⽂本区域(text region)、数据区域(data region)和堆栈(stackregion);
  • 进程在系统中独⽴存在,拥有⾃⼰独⽴的资源,多个进程可以在单个处理器上并发执⾏且互不影响;
    操作系统可以同时执⾏多个任务,每个任务就是进程。
  • 进程状态:进程有三个状态:就绪、运⾏和阻塞。
  • 就绪状态其实就是获取了除CPU之外的所有资源,只要处理器分配资源就可以⻢上执⾏。就绪状态有排队序列什么的,排队原则不再赘述;
  • 运⾏态就是获得了处理器分配的资源,程序开始执⾏;
  • 阻塞态,当程序条件不够时候,需要等待条件满⾜时候才能执⾏,如等待i/o操作时候,此刻的状态就叫阻塞态。
  1. 线程
  • 线程是CPU的基本调度单位;
  • 线程是在进程之后发展出来的概念,线程也叫轻量级进程;
  • 通常⼀个进程包含若⼲个线程,当然⼀个进程中⾄少有⼀个线程,不然没有存在的意义;
  • 线程可以利⽤进程所拥有的资源,在引⼊线程的操作系统中,通常都是把进程作为分配资源的基本单位,⽽把线程作为独⽴运⾏和独⽴调度的基本单位;
  • 由于线程⽐进程更⼩,基本上不拥有系统资源,故对它的调度所付出的开销就会⼩得多,能更⾼效的提⾼系统多个程序间并发执⾏的程度。
  • 例如:杀毒软件程序是⼀个进程,该程序在为计算机进⾏检查的同时,可以清理垃圾⽂件,并进⾏⽇志记录。检查计算机、清理垃圾⽂件、⽇志记录这就是线程。
  • 例如:启动word⽂档就是运⾏了⼀个进程,⽂字录⼊时,可以进⾏拼写错误检查,并使⾸字⺟⼤写。⽂字录⼊、拼写错误检查、⾸字⺟⼤写就属于word操作进程中的线程。
(⼆)、进程与线程的区别

1、进程和线程的主要差别在于它们是不同的操作系统资源管理⽅式。
进程有独⽴的地址空间,⼀个进程崩溃后,在保护模式下不会对其它进程产⽣影响,⽽线程只是⼀个进程中的不同执⾏路径。线程有⾃⼰的堆栈和局部变量,但线程之间没有单独的地址空间,⼀个线程死掉就等于整个进程死掉,所以多进程的程序要⽐多线程的程序健壮,但在进程切换时,耗费资源较⼤,效率要差⼀些。但对于⼀些要求同时进⾏并且⼜要共享某些变量的并发操作,只能⽤线程,不能⽤进程。

  1. 简⽽⾔之,⼀个程序⾄少有⼀个进程,⼀个进程⾄少有⼀个线程;
  2. 线程的划分尺度⼩于进程,使得多线程程序的并发性⾼;
  3. 另外,进程在执⾏过程中拥有独⽴的内存单元,⽽多个线程共享内存,从⽽极⼤地提⾼了程序的运⾏效率。
  4. 线程在执⾏过程中与进程还是有区别的。每个独⽴的进程有⼀个程序运⾏的⼊⼝、顺序执⾏程序。但是线程不能够独⽴执⾏,必须依存在应⽤程序中,由应⽤程序提供多个线程执⾏控制。
  5. 从逻辑⻆度来看,多线程的意义在于⼀个应⽤程序中,有多个执⾏部分可以同时执⾏。但操作系统并没有将多个线程看做多个独⽴的应⽤,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
    6)线程执⾏开销⼩,但不利于资源的管理和保护;⽽进程正相反。同时,线程适合于在SMP(多核处理机)机器上运⾏,⽽进程则可以跨机器迁移。
(三)、相关背景知识
  1. 进程和线程都是⼀个时间段的描述,是CPU⼯作时间段的描述,不过是颗粒⼤⼩不同。
  • CPU+RAM+各种资源(⽐如显卡、GPU)构成我们的电脑,但是电脑的运⾏,实际就是CPU和相关寄存器以及RAM之间的事情。
  • ⼀个最最基础的事实:CPU太快,太快,太快了,寄存器仅仅能够追的上他的脚步,RAM和别的挂在各总线上的设备完全是望其项背。那当多个任务要执⾏的时候怎么办呢?轮流着来?或者谁优先级⾼谁来?不管怎么样的策略,⼀句话就是在CPU就是轮流着来。
  • ⼀个必须知道的事实:执⾏⼀段程序代码,实现⼀个功能的过程介绍 ,当得到CPU的时候,相关的资源必须也已经就位,就是显卡啊,GPU什么的必须就位,然后CPU开始执⾏。这⾥除了CPU以外所有的就构成了这个程序的执⾏环境,也就是我们所定义的程序上下⽂。当这个程序执⾏完了,或者分配给他的CPU执⾏时间⽤完了,那它就要被切换出去,等待下⼀次CPU的临幸。在被切换出去的最后⼀步⼯作就是保存程序上下⽂,因为这个是下次他被CPU临幸的运⾏环境,必须保存。
  • 串联起来的事实:前⾯讲过在CPU看来所有的任务都是⼀个⼀个的轮流执⾏的,具体的轮流⽅法就是:先加载程序A的上下⽂,然后开始执⾏A,保存程序A的上下⽂,调⼊下⼀个要执⾏的程序B的程序上下⽂,然后开始执⾏B,保存程序B的上下⽂。。。。
  • 进程就是包换上下⽂切换的程序执⾏时间总和 = CPU加载上下⽂ + CPU执⾏ + CPU保存上下⽂
  • 线程是什么呢?
    • 进程的颗粒度太⼤,每次都要有上下的调⼊,保存,调出。如果我们把进程⽐喻为⼀个运⾏在电脑上的软件,那么⼀个软件的执⾏不可能是⼀条逻辑执⾏的,必定有多个分⽀和多个程序段,就好⽐要实现程序A实际分成 a,b,c等多个块组合⽽成。那么这⾥具体的执⾏就可能变成:程序A得到CPU -> CPU加载上下⽂,开始执⾏程序A的a⼩段,然后执⾏A的b⼩段,然后再执⾏A的c⼩段,最后CPU保存A的上下⽂。
    • 这⾥a,b,c的执⾏是共享了A的上下⽂,CPU在执⾏的时候没有进⾏上下⽂切换的。这⾥的a,b,c就是线程,也就是说线程是共享了进程的上下⽂环境的更为细⼩的CPU时间段。
  1. 操作系统的设计,可归结为三点:
  • (1)以多进程形式,允许多个任务同时运⾏;
  • (2)以多线程形式,允许单个任务分成不同的部分运⾏;
  • (3)提供协调机制,⼀⽅⾯防⽌进程之间和线程之间产⽣冲突,另⼀⽅⾯允许进程之间和线程之间共享资源。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/990932.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号