目录

  • Go并发优势
  • goroutine
    • goroutine定义
      • 线程和协程的区别
      • 创建goroutine
  • runtime包
    • Gosched()
    • Goexit()
    • GOMAXPROCS()

Go并发优势

Go语言最大的特点就是从语言层面支持并发,开发者不用担心并发的底层逻辑、内存管理,只需要编写好自己的业务逻辑即可。Go语言也提供了十分强大的垃圾回收机制,开发者不用担心创建的量如何销毁。

在其他语言中,编写并发程序往往需要使用其他的并发库才能实现。而在Go语言里,想要编写一个并发程序是非常容易的事情,它不需要额外引用其他的第三方库,只需要使用“go”关键字就可以实现。

在Go语言里,只需要使用"go"加上函数名称就可以让这个函数变为并发函数,如下示例:

package mainfunc run(arg string) {// 此线程的任务
}func main() {go run("this is new thread")
}

Go语言的并发基于CSP(Communication Sequential Process,通信顺序进程)模型,CSP模型是用于描述两个独立的并发实体通过共享的通信管道(channel)进行通信的并发模型。

CSP中channel是一类对象,它不关注发送消息的实体,而关注发送消息时使用的通信管道。 简单来说,CSP模型提倡通过通信来共享内存,而非通过共享内存来通信。

基于CSP模型,Go语言通过通信的方式,通过安全的通道发送和接收数据以实现同步,避免了显式锁的问题,大大简化了并发编程的编写。

goroutine

goroutine是Go并发设计的核心,也叫协程,它比线程更加轻量,因此可以同时运行成千上万个并发任务。

不仅如此,Go语言内部已经实现了goroutine之间的内存共享,它比线程更加易用、高效和轻便。

goroutine定义

在Go语言中,每一个并发的执行单元叫作一个goroutine。我们只需要在调用的函数前面添加go关键字,就能使这个函数以协程的方式运行。

go 函数名(函数参数)

一旦我们使用了go关键字,函数的返回值就会被忽略,故不能使用函数返回值来与主线程进行数据交换,而只能使用channel。

线程和协程的区别

协程和线程最重要的区别在于:

  1. 线程切换需要陷入内核,然后进行上下文切换,而协程在用户态由协程调度器完成,不需要陷入内核,这样代价就小了。
  2. 协程的切换时间点是由调度器决定,而不是由系统内核决定的,尽管它们的切换点都是时间片超过一定阈值,或者是进入I/O或睡眠等状态时。
  3. 基于垃圾回收的考虑,Go实现了垃圾回收,但垃圾回收的必要条件是内存位于一致状态,因此就需要暂停所有的线程。如果交给系统去做,那么会暂停所有的线程使其一致。但对于Go语言来说,调度器知道什么时候内存位于一致状态,所以也就没有必要暂停所有运行的线程。

线程有固定的栈,基本都是2 MB,都是固定分配的;这个栈用于保存局部变量,在函数切换时使用。但是对于goroutine来说,一个大小固定的栈可能会导致资源浪费,所以Go采用了动态扩张收缩的策略,初始化为2KB,最大可扩张到1GB。

创建goroutine

当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们称之为main goroutine。所有的goroutine在main函数结束时会一并结束。

我们只需要在函数调用语句前面添加go关键字,就可以创建并发执行单元。开发人员无须了解任何执行细节,调度器会自动将其安排到合适的系统线程上去执行。

go 函数名(参数名)

runtime包

Go语言中runtime(运行时)包实现了一个小型的任务调度器。这个调度器的工作原理和系统对线程的调度类似,Go语言调度器可以高效地将CPU资源分配给每一个任务。以下主要介绍三个函数:Gosched()Goexit()GOMAXPROCS()

Gosched()

// Gosched yields the processor, allowing other goroutines to run. It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched() {checkTimeouts()mcall(gosched_m)
}

Gosched()使当前Go协程放弃处理器,以让其他Go协程运行。它不会挂起当前Go协程,因此当前Go协程未来会恢复执行。

如下示例:

package mainimport ("fmt""runtime"
)func main() {go func() {for i := 0; i < 3; i++ {fmt.Println("go")}}()for i := 0; i < 2; i++ {runtime.Gosched()fmt.Println("main")}
}

运行结果如下:

Go语言的协程是抢占式调度的,当遇到长时间执行或者进行系统调用时,会主动把当前goroutine的CPU §转让出去,让其他goroutine能被调度并执行。

一般出现如下几种情况,goroutine就会发生调度:

  1. syscall
  2. C函数调用(本质上和syscall一样)
  3. 主动调用runtime.Gosched
  4. 某个goroutine的调用时间超过100ms,并且这个goroutine调用了非内联的函数。

Goexit()

// Goexit terminates the goroutine that calls it. No other goroutine is affected.
// Goexit runs all deferred calls before terminating the goroutine. Because Goexit
// is not a panic, any recover calls in those deferred functions will return nil.
//
// Calling Goexit from the main goroutine terminates that goroutine
// without func main returning. Since func main has not returned,
// the program continues execution of other goroutines.
// If all other goroutines exit, the program crashes.
func Goexit()

Goexit()终止调用它的Go协程,但其他Go协程不会受影响。Goexit()会在终止该Go协程前执行所有defer的函数。

如下示例:

package mainimport ("fmt""runtime""time"
)func Task1() {defer fmt.Println("task1 stop")fmt.Println("task1 start")fmt.Println("task1 work")
}func Task2() {defer fmt.Println("task2 stop")fmt.Println("task2 start")runtime.Goexit() // 效果和return一样fmt.Println("task2 work")
}func main() {go Task1()go Task2()time.Sleep(time.Second * 5)
}

运行结果如下:

GOMAXPROCS()

GOMAXPROCS(n int)函数可以设置程序在运行中所使用的CPU数,Go语言程序默认会使用最大CPU数进行计算。

// GOMAXPROCS sets the maximum number of CPUs that can be executing
// simultaneously and returns the previous setting. It defaults to
// the value of runtime.NumCPU. If n < 1, it does not change the current setting.
// This call will go away when the scheduler improves.
func GOMAXPROCS(n int) int

GOMAXPROCS()设置可同时执行的最大CPU数,并返回先前的设置。若n < 1,它就不会更改当前设置。本地机器的逻辑CPU数可通过NumCPU查询。

package mainimport ("fmt""runtime""time"
)func main() {n := runtime.GOMAXPROCS(1)fmt.Println("先前的CPU核数设置为: ", n)last := time.Now()for i := 0; i < 100000; i++ {go func() {// 耗时任务a := 999999 ^ 9999999a = a + 1}()}now := time.Now()fmt.Println(now.Sub(last))
}

运行结果如下:

当改为12核进行计算时,效率得到了显著的提升,运行结果如下:

Go语言中的goroutine相关推荐

  1. go语言中的goroutine(协程)

    文章目录 goroutine(协程) 1.进程和线程说明: 2.并发和并行说明: 3.go协程和go主线程: 4.MPG 模式基本介绍 5.设置golang运行的cpu数 goroutine(协程) ...

  2. go语言中channel的创建和销毁以及匿名函数的使用

    channel的创建 go语言中,任意类型前面加上关键字chan即可声明对应类型的通道,创建通道需要使用make,make也用于map 和slice的创建 创建一个通道 /*刚创建的通道是nil*/ ...

  3. Go语言中 defer 的用法

    文章目录 Go语言中 defer 的用法 一.defer触发时机 二.defer执行逻辑 1. 多个defer语句按先进后出的方式执行 2.defer声明时,对应的参数会实时解析 3.defer.re ...

  4. C语言中typeof作用,浅析C语言中typeof关键字用法

    浅析C语言中typeof关键字用法 前言 C语言中 typeof 关键字是用来定义变量数据类型的.在linux内核源代码中广泛使用. 下面是Linux内核源代码中一个关于typeof实例: #defi ...

  5. c语言中struct和c++中class实例对比

    前言 实现游戏中简单的打怪升级的功能 c语言中的struct #include <stdio.h>typedef void(*Train)(struct player*, int); ty ...

  6. 关于C语言中printf函数“输出歧视”的问题

    目录 关于C语言中printf函数"输出歧视"的问题 问题描述 探索问题原因 另一种研究方法 问题结论 关于C语言中printf函数"输出歧视"的问题 问题描述 ...

  7. C语言中“野指针”、“悬空指针”是什么?

    目录 1."野指针"(wild pointer) 2."悬空指针"(dangling pointer) 1."野指针"(wild point ...

  8. c+语言+null,C/C++语言中NULL、'\0’和0的区别

    NULL.'\0'和0的值是一样的,都是0,不过它们的表现形式不一样: 1. NULL: 即空指针,不过在C和C++中并不一样.在VS 2013的库文件string.h中可以看到如果定义. 1 /* ...

  9. 关于C语言中的malloc和free函数的用法

    一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...

最新文章

  1. Java中常见的几种类型转换
  2. java字符_Java String 类
  3. pInvokeStackImbalance 调试异常的解决办法。
  4. 机器学习实战:TypeError: unhashable type: 'matrix'
  5. 初级线段树讲解---转
  6. html网页加密最终版,【原】记一次加密网页html的研究
  7. POJ 1088----滑雪(DP)
  8. 分子结构模拟工具UCSF Chimera的安装及基本操作
  9. Matplotlib 中文用户指南 3.3 使用 GridSpec 自定义子图位置
  10. python创建列表副本的方法_Python之列表方法
  11. 朴素贝叶斯算法_C语言实现朴素贝叶斯算法(Naive Bayes)
  12. 如何结束vbs的代码
  13. Android基于腾讯云的小直播开发步骤
  14. python图书管理实训报告总结_图书管理系统实训报告正文
  15. java语言的数组描述_下列关于java语言的数组描述中,错误的是( )
  16. ZBrush建模的15个小技巧,萌新小白都用得上的干货,速看
  17. 花生壳内网穿透操作文档
  18. nyoj-动态规划-234-吃土豆-201308131021
  19. 标准差np.std()
  20. 一起Talk Android吧(第三百一十七回:Android中的虚拟按键)

热门文章

  1. 以管理员身份运行cmd
  2. 计算机英语趣味学习,趣味英语教学方法
  3. 百练4133:垃圾炸弹
  4. 3月1日第壹简报,星期三,农历二月初十
  5. CRM开发总结2:BOL找字段层级关系
  6. matlab 图像拼接算法,MATLAB图像拼接算法及实现
  7. 安全架构-api接口安全设计
  8. 一个IT王老五的情感自白书
  9. 【聊天表情包小程序的开发】之开发简介
  10. 笔记本电脑打开后不显示桌面_电脑打开之后黑屏?出来不了桌面咋办啊?