Golang 协程(goroutine) 运行过程 与 并发


本文摘自网络,作者,侵删。

首先我们需要理解进程和线程的关系

当运行一个应用程序的时候,操作系统会为这个应用程序启动一个进程,该个进程包含了应用程序在运行中所用需要用到和维护的各种资源的容器

  • 每个进程至少包含一个线程
  • 每个进程的初始线程被称为主线程
  • 执行线程的空间是应用程序本身的空间
  • 主线程终止,应用程序也将终止

goroutine执行过程

前提,goroutine的执行主要依靠调度处理器来完成,如
// 创建了两个调度处理器
runtime.GOMAXPROCS(2)

1、创建一个goroutine
2、goroutine进入调度处理器全局运行队列(调度器)中
3、调度器分配一个调度处理器供goroutine使用
4、goroutine 执行

在其上述执行过程中,我们很容易会思考到一个问题,例如现在有 3 个goroutine等待执行,那么,goroutine是如何运行的呢

我们来尝试执行一段代码

import (
"fmt"
"runtime"
"sync"
)

func main()  {
    // 创建一个调度处理器
    runtime.GOMAXPROCS(1)

    var wg sync.WaitGroup
    wg.Add(2)

    fmt.Println("协程开始 ...\n")

    go func() {
        defer wg.Done()

        for count :=0; count < 3; count++ {
            for char := 'a'; char < 'a' + 26; char ++ {
                fmt.Printf("%c", char)
            }
        }
    }()

    go func() {
        defer wg.Done()

        for count :=0; count < 3; count++ {
            for char := 'A'; char < 'A' + 26; char ++ {
                fmt.Printf("%c", char)
            }
        }
    }()

    fmt.Println("wait ...\n")
    wg.Wait()

    fmt.Println("\n结束...")
}

结果

协程开始 ...
wait ...
ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
结束...

我们会发现,是不是第二goroutine先执行完毕?是的,不管是尝试多少次,都会是这个结果

其实,导致这个问题的原因来自于其管理goroutine寿命的行为

goroutine中,为了防止某个goroutine运行时间过长,调度器会停止当前正在运行的goroutine,给其他goroutine运行的机会

继续查看代码

package main

import (
"fmt"
"runtime"
"sync"
)

func main()  {
    runtime.GOMAXPROCS(1)

    var wg sync.WaitGroup
    wg.Add(3)

    fmt.Println("协程开始 ...\n")

    go func() {
        defer wg.Done()

        fmt.Println(1)
    }()

    go func() {
        defer wg.Done()

        fmt.Println(2)
    }()
    go func() {
        defer wg.Done()

        fmt.Println(3)
    }()

    fmt.Println("wait ...\n")
    wg.Wait()

    fmt.Println("\n结束...")
}

结果则为 3 1 2

并发与并行

简而言之

  • 并行

不用的程序在不同的物理处理器上执行,关键的在于同时做很多事情

  • 并发

使用较少的资源做更多的事情,即在go中为,用聪明的算法根据单个物理机器,调度一个个执行

go中,如何实现并行


// 双核
runtime.GOMAXPROCS(2)

即可

以上,会触发2两调度处理器,并发运行,但实际上这种并发也其实就是 go 通过单个物理机器创建多个线程实现的伪并行

IO操作下的goroutine

IO下的goroutine都为阻塞性的goroutine

  • 资源读写IO

调用时,线程将从逻辑处理器上分离,线程继续堵塞,处理器将绑定一个新的线程,并执行其他 goroutineIO goroutine 执行完毕后,占用线程进行回收,下次使用

  • 网络IO

网络IO,将从逻辑处理器上分离,且将其放入到网络轮询器的运行中,当检测到改资源IO操作就绪,将取出并分配到逻辑处理器上重新运行

调度器配置

Go 默认支持最多创建10000个线程,如果使用的再多,可能会崩溃,可以通过runtime或者debug的包来完成这些配置


本文来自:Segmentfault

感谢作者:邓锋

查看原文:Golang 协程(goroutine) 运行过程 与 并发

相关阅读 >>

vim安装Go插件vim-GoGocode,支持代码高亮、代码提示和语法检查等功能

docker 概述

Go-zero 是如何追踪你的请求链路?

Golang 入门系列(二)学习Go语言需要注意的坑

必须掌握的Golang23种设计模式之工厂方法模式

Go time

最简单的Go dockerfile编写姿势,没有之一!

专业技能:熟练安装各种软件???

“python太慢了、Golang糟透了、monGodb是最好的”:那些关于软件工程的“宗教”辩论

Golang中的print与fmt的区别

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...