美文网首页微服务
Go语言轻量线程goroutine

Go语言轻量线程goroutine

作者: 码二哥 | 来源:发表于2020-02-13 10:50 被阅读0次

    参考:
    http://c.biancheng.net/view/93.html

    关键点:

    通过关键词汇,实现快速理解,记忆目的

    1、goroutine 解决了什么问题

    A、goroutine提供了一种机制,就是,当用户分配创建很多任务的时候,系统能够自动及时的将这些任务分配CPU上,让这些任务尽量实现并发运行。

    B、省去了让用户自己去处理任务和CPU之间的对应关系,用户无需再关心任务CPU之间的关系了。

    2、goroutine 特性

    • 由Go运行时runtime管理调度

    • 在程序启动时,会为main函数创建一个默认的goroutine

    • 在go语言里,所有的函数都是运行在goroutine中的

    3、使用goroutine的几种方式?或者写法

    A、go 普通函数

    B、go 匿名函数

    4、主main协程结束时,所有协程也会结束

    1、使用普通函数创建 goroutine

    Go 程序中使用 go 关键字为一个函数创建一个 goroutine。

    一个函数可以被创建多个 goroutine,一个 goroutine 必定对应一个函数。

    1) 格式

    为一个普通函数创建 goroutine 的写法如下:

    go 函数名( 参数列表 )
    
    • 函数名:要调用的函数名。

    • 参数列表:调用函数需要传入的参数。

    使用 go 关键字创建 goroutine 时,被调用函数的返回值会被忽略。

    如果需要在 goroutine 中返回数据,请使用后面介绍的通道(channel)特性,通过通道把数据从 goroutine 中作为返回值传出。

    2) 例子

    使用 go 关键字,将 running() 函数并发执行,每隔一秒打印一次计数器,而 main 的 goroutine 则等待用户输入,两个行为可以同时进行。请参考下面代码:

    package main
    import (
        "fmt"
        "time"
    )
    func running() {
        var times int
        // 构建一个无限循环
        for {
            times++
            fmt.Println("tick", times)
            // 延时1秒
            time.Sleep(time.Second)
        }
    }
    func main() {
        // 并发执行程序
        go running()
        // 接受命令行输入, 不做任何事情
        var input string
        fmt.Scanln(&input)
    }
    

    命令行输出如下:

    tick 1
    tick 2
    tick 3
    tick 4
    tick 5
    
    

    代码执行后,命令行会不断地输出 tick,同时可以使用 fmt.Scanln() 接受用户输入。两个环节可以同时进行。

    代码说明如下:

    • 第 12 行,使用 for 形成一个无限循环。

    • 第 13 行,times 变量在循环中不断自增。

    • 第 14 行,输出 times 变量的值。

    • 第 17 行,使用 time.Sleep 暂停 1 秒后继续循环。

    • 第 25 行,使用 go 关键字让 running() 函数并发运行。

    • 第 29 行,接受用户输入,直到按 Enter 键时将输入的内容写入 input 变量中并返回,整个程序终止。

    这段代码的执行顺序如下图所示。


    图:并发运行图

    这个例子中,Go 程序在启动时,运行时(runtime)会默认为 main() 函数创建一个 goroutine。

    在 main() 函数的 goroutine 中执行到 go running 语句时,归属于 running() 函数的 goroutine 被创建,running() 函数开始在自己的 goroutine 中执行。

    此时,main() 继续执行,两个 goroutine 通过 Go 程序的调度机制同时运作。

    go协程-调用普通函数方式 go协程-调用别的包下的普通函数方式

    2、使用匿名函数创建goroutine

    go 关键字后也可以为匿名函数或闭包启动 goroutine。

    1) 使用匿名函数创建goroutine的格式

    使用匿名函数或闭包创建 goroutine 时,除了将函数定义部分写在 go 的后面之外,还需要加上匿名函数的调用参数,格式如下:

    go func( 参数列表 ){
        函数体
    }( 调用参数列表 )
    

    其中:

    • 参数列表:函数体内的参数变量列表。

    • 函数体:匿名函数的代码。

    • 调用参数列表:启动 goroutine 时,需要向匿名函数传递的调用参数。

    2) 使用匿名函数创建goroutine的例子

    在 main() 函数中创建一个匿名函数并为匿名函数启动 goroutine。匿名函数没有参数。代码将并行执行定时打印计数的效果。参见下面的代码:

    package main
    import (
        "fmt"
        "time"
    )
    func main() {
        go func() {
            var times int
            for {
                times++
                fmt.Println("tick", times)
                time.Sleep(time.Second)
            }
        }()
        var input string
        fmt.Scanln(&input)
    }
    

    代码说明如下:

    • 第 10 行,go 后面接匿名函数启动 goroutine。

    • 第 12~19 行的逻辑与前面程序的 running() 函数一致。

    • 第 21 行的括号的功能是调用匿名函数的参数列表。由于第 10 行的匿名函数没有参数,因此第 21 行的参数列表也是空的。

    go协程-直接调用匿名函数方式

    3、提示

    所有 goroutine 在 main() 函数结束时会一同结束

    goroutine 虽然类似于线程概念,但是从调度性能上没有线程细致,而细致程度取决于 Go 程序的 goroutine 调度器的实现和运行环境。

    终止 goroutine 的最好方法就是自然返回 goroutine 对应的函数。

    虽然可以用 golang.org/x/net/context 包进行 goroutine 生命期深度控制,这种方法仍然处于内部试验阶段,并不是官方推荐的特性。

    截止 Go 1.9 版本,暂时没有标准接口获取 goroutine 的 ID。

    相关文章

      网友评论

        本文标题:Go语言轻量线程goroutine

        本文链接:https://www.haomeiwen.com/subject/bojkfhtx.html