Goroutine | 豆包MarsCode AI刷题

101 阅读5分钟

Goroutine

多线程

普通方法调用 对比 多线程

普通方法调用: 串行

 main(){ // 串行执行 1/2/3
     test1()
     test2()
     test3()
 }

多线程

 main(){ // 4个线程同时执行:main test1  test2 test3 、交替的快速执行。
    go test1()
    go test2()
    go test3()
 }

进程、线程、协程

程序: 指令和数据的一个有序集合。本身没有任何含义,是一个静态的概念。

进程:QQ.exe 微信 .... 一个个的程序、执行起来之后,开启一个进程。执行程序的一次执行过程,它是动态的概念

  • 系统资源分配的单位。

线程: 一个进程中可以有多个线程,并行的,一个进程之中,至少要有一个线程。main 主线程

  • 线程是CPU调度和执行的单位。

  • 一个线程,直接执行就可以了

  • 多个线程:CPU如何调度执行。 一个CPU、也是可以跑多个线程的。

    • 并发
    • 并行
  • 在代码级别中的所谓多线程并发处理问题。模拟出来的

  • 真正的多线程是指的拥有多个CPU、多核

  • 如果是模拟出来的多线程、即在一个CPU的情况下,在同一个时间点,只能执行一个线程的代码

  • 因为执行的速度很快,所以就有了同时在执行的一种错句。

并行真的就最快吗?

  • 并行运行的组件,考虑到多个线程之间的通信问题,这种跨CPU通信问题是开销比较高的,并行并不一定快。

进程、线程、协程

进程(Process),线程(Thread), 协程(Coroutine, 也叫轻量级线程)

进程

进程是一个程序在一个数据集中的一次动态执行过程,可以简单理解为“正在执行的程序" ,它是CPU资源分配和调度的独立单位。

进程一般由程序、数据集、进程控制块三部分组成。我们编写的程序用来描述进程要完成哪些功能以及如何完成;

数据集则是程序在执行过程中所需要使用的资源;进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。 进程的局限是创建、撤销和切换的开销比较大

线程 :

线程是在进程之后发展出来的概念。线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、 程序计数器、寄存器集合和堆栈共同组成。一个进程可以包含多个线程。

线程的优点是减小了程序并发执行时的开销,提高了操作系统的并发性能缺点是线程没有自己的系统资源,同一进程的各线程可以共享进程所拥有的系统资源,如果把进程比作一个车间,那么线程就好比是车间里面的工人。 不过对于某些独占性资源存在锁机制,处理不当可能会产生”死锁"。

协程Goroutine

协程是一种用户态的轻量级线程,又称微线程,英文名Coroutine,协程的调度完全由用户控制。人们通常将协程和子程序(函数)比较着理解。

就好比是启动了一个函数,单次执行完毕它。不影响我们main线程的执行。

子程序调用总是一个入口,一次返回,一旦退出即完成了子程序的执行。

与传统的系统级线程和进程相比,协程的最大优势在于其"轻量级”可以轻松创建上百万个而不会导致系统资源衰竭,而线程和进程通常最多也不能超过1万的。这也是协程也叫轻量级线程的原因。 Go中使用Goroutine来实现并发concurrently

Goroutine是Go语言特有的名词。 区别于进程Process,线程Thread, 协程Goroutine, 因为Go语言的创造者们觉得和他们是有所区别的,所以专门创造了Goroutine

Goroutine是与其他函数或方法同时运行的函数或方法。Goroutines可以被认为是轻量级的线程。与线程相比,创建Goroutine的成本很小,它就是一段代码,一个函数入口。以及在堆上为其分配的一个堆栈(初始大小为4K,会随着程序的执行自动增长删除)。因此它非常廉价,Go应用程序可以轻松并发运行数千个Goroutines

在go语言中使用 goroutine,在调用函数或者方法前面加上 go 关键字即可

 // 方法调用
 main(){
     test()
 }
 // goroutine 
 main(){
    go test()
 }

goroutine

 package main
 ​
 import "fmt"
 ​
 func main() {
    // goroutine : 和普通方法调用完全不同,它是并发执行的,快速交替。
    go hello()
    for i := 0; i < 1000; i++ {
       fmt.Println("main - ", i)
    }
 }
 ​
 // hello函数
 func hello() {
    for i := 0; i < 1000; i++ {
       fmt.Println("hello - ", i)
    }
 }

我们需要了解Goroutine的规则

1、当新的Goroutine开始时, Goroutine调用立即返回。与函数不同,go不等待Goroutine执行结束

2、当Goroutine调用,并且Goroutine的任何返回值被忽略之后,go立即执行到下一行代码

3、main的Goroutine应该为其他的Goroutines执行。如果main的Goroutine终止了,程序将被终止,而其他Goroutine将不会运行