首页 > 编程语言 >Go基础编程:并发编程—goroutine

Go基础编程:并发编程—goroutine

时间:2022-09-28 19:04:15浏览次数:55  
标签:main 编程 fmt goroutine go func Go runtime


1 goroutine是什么

goroutine是Go并行设计的核心。goroutine说到底其实就是协程,但是它比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB),当然会根据相应的数据伸缩。也正因为如此,可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。

2 创建goroutine

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

在并发编程里,我们通常想讲一个过程切分成几块,然后让每个goroutine各自负责一块工作。当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine。新的goroutine会用go语句来创建。

示例代码:

package main

import (
"fmt"
"time"
)

func newTask() {
i := 0
for {
i++
fmt.Printf("new goroutine: i = %d\n", i)
time.Sleep(1 * time.Second) //延时1s
}
}

func main() {
//创建一个 goroutine,启动另外一个任务
go newTask()

i := 0
//main goroutine 循环打印
for {
i++
fmt.Printf("main goroutine: i = %d\n", i)
time.Sleep(1 * time.Second) //延时1s

程序运行结果:

Go基础编程:并发编程—goroutine_并发

3 主goroutine先退出

主goroutine退出后,其它的工作goroutine也会自动退出:

func newTask() {
i := 0
for {
i++
fmt.Printf("new goroutine: i = %d\n", i)
time.Sleep(1 * time.Second) //延时1s
}
}

func main() {
//创建一个 goroutine,启动另外一个任务
go newTask()

fmt.Println("main goroutine exit")
}

程序运行结果:

Go基础编程:并发编程—goroutine_Go_02

4 runtime包

4.1 Gosched

runtime.Gosched() 用于让出CPU时间片,让出当前goroutine的执行权限,调度器安排其他等待的任务运行,并在下次某个时候从该位置恢复执行。

这就像跑接力赛,A跑了一会碰到代码runtime.Gosched() 就把接力棒交给B了,A歇着了,B继续跑。

示例代码:

func main() {
//创建一个goroutine
go func(s string) {
for i := 0; i < 2; i++ {
fmt.Println(s)
}
}("world")

for i := 0; i < 2; i++ {
runtime.Gosched() //import "runtime"
/*
屏蔽runtime.Gosched()运行结果如下:
hello
hello

没有runtime.Gosched()运行结果如下:
world
world
hello
hello
*/
fmt.Println("hello")
}
}

4.2 Goexit

调用 runtime.Goexit() 将立即终止当前 goroutine 执⾏,调度器确保所有已注册 defer 延迟调用被执行。

示例代码:

func main() {
go func() {
defer fmt.Println("A.defer")

func() {
defer fmt.Println("B.defer")
runtime.Goexit() // 终止当前 goroutine, import "runtime"
fmt.Println("B") // 不会执行
}()

fmt.Println("A") // 不会执行
}() //别忘了()

//死循环,目的不让主goroutine结束
for

程序运行结果:

Go基础编程:并发编程—goroutine_并发_03

4.3 GOMAXPROCS

调用 runtime.GOMAXPROCS() 用来设置可以并行计算的CPU核数的最大值,并返回之前的值。

示例代码:

func main() {
//n := runtime.GOMAXPROCS(1) //打印结果:111111111111111111110000000000000000000011111...
n := runtime.GOMAXPROCS(2) //打印结果:010101010101010101011001100101011010010100110...
fmt.Printf("n = %d\n", n)

for {
go fmt.Print(0)
fmt.Print(1)}
}

在第一次执行(runtime.GOMAXPROCS(1))时,最多同时只能有一个goroutine被执行。所以
会打印很多1。过了一段时间后,GO调度器会将其置为休眠,并唤醒另一个goroutine,这时候就开始打印很多0了,在打印的时候,goroutine是被调度到操作系统线程上的。

在第二次执行(runtime.GOMAXPROCS(2))时,我们使用了两个CPU,所以两个goroutine可以一起被执行,以同样的频率交替打印0和1。

标签:main,编程,fmt,goroutine,go,func,Go,runtime
From: https://blog.51cto.com/u_3002289/5720709

相关文章

  • Go基础编程:基础数据类型
    分类Go语言内置以下这些基础类型:类型名称长度零值说明bool布尔类型1false其值不为真即为假,不可以用数字代表true或falsebyte字节型10uint8别名rune字符类型40专用于存储unic......
  • python-并发编程
    目录01、理论多道技术null02、进程进程运行的三状态图同步和异步阻塞和非阻塞开启进程的两种方式进程对象的join方法进程之间数据相互隔离(默认情况下)进程对象及其他方法僵......
  • golang 的双向循环链表
                如下为go实现的双向循环列表。packagemainimport("fmt")typeRingstruct{prev,......
  • 【C++】从零开始的CS:GO逆向分析2——配置GLFW+IMGUI环境并创建透明窗口
    【C++】从零开始的CS:GO逆向分析2——配置GLFW+IMGUI环境并创建透明窗口 使用的环境:VisualStudio2017,创建一个控制台程序作为工程文件1.配置glfw在github上下载GLFW......
  • Go基础编程:自定义函数
    定义格式函数构成代码执行的逻辑结构。在Go语言中,函数的基本组成为:关键字func、函数名、参数列表、返回值、函数体和返回语句。Go语言函数定义格式如下:funcFuncName(/*参......
  • Go基础编程:递归函数、函数类型、匿名函数与闭包
    1.递归函数递归指函数可以直接或间接的调用自身。递归函数通常有相同的结构:一个跳出条件和一个递归体。所谓跳出条件就是根据传入的参数判断是否需要停止递归,而递归体则是......
  • Go基础编程:工作区
    工作区介绍Go代码必须放在工作区中。工作区其实就是一个对应于特定工程的目录,它应包含3个子目录:src目录、pkg目录和bin目录。src目录:用于以代码包的形式组织并保存Go源码文......
  • Go基础编程:作用域
    作用域为已声明标识符所表示的常量、类型、变量、函数或包在源代码中的作用范围。局部变量在函数体内声明的变量、参数和返回值变量就是局部变量,它们的作用域只在函数体内:fu......
  • Go基础编程:工程管理
    概述在实际的开发工作中,直接调用编译器进行编译和链接的场景是少而又少,因为在工程中不会简单到只有一个源代码文件,且源文件之间会有相互的依赖关系。如果这样一个文件一个......
  • Go基础编程:复合类型—指针
    指针是一个代表着某个内存地址的值。这个内存地址往往是在内存中存储的另一个变量的值的起始位置。Go语言对指针的支持介于Java语言和C/C++语言之间,它既没有想Java语言那样......