微服务

Go语言轻量线程goroutine

2020-02-13  本文已影响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() 接受用户输入。两个环节可以同时进行。

代码说明如下:

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


图:并发运行图

这个例子中,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( 参数列表 ){
    函数体
}( 调用参数列表 )

其中:

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)
}

代码说明如下:

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

3、提示

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

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

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

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

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

上一篇下一篇

猜你喜欢

热点阅读