Golang Goroutine 初识

Justin910 · · 986 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

相信大家对线程并不陌生,顾名思义就是同时做多件事情,线程对于编程语言的重要性不言而喻。在开发App时经常需要开启线程去处理一些耗时的操作,在做服务器开发也是需要开启多线程去处理多个客户端的请求。当时众所周知线程是属于系统层面上的东西,开启线程会耗费很多资源且不易管理。

GoroutineGo语言面向线程的轻量级方法( 注: Goroutine不是线程 ),创建Goroutine的成本很低,只需要几千个字节的额外内存,这使同时运行成千上万个Goroutine成为可能。

Goroutine 也 非常的容易上手,只需要一行 go func(...) 就可以了。下面我们来实践一下,创建一个简单的Goroutine

package main

import (
    "fmt"
)

func RunLoop(){

    for i := 0; i < 10; i++ {
        fmt.Printf("%d ", i)
    }
}

func main(){

    go func() {  //开启goroutine
        RunLoop()
    }()

    RunLoop()
}

打印输出:

0 1 2 3 4 5 6 7 8 9 

goroutine还没有开始执行,程序就结束了。导致只打印了一次0~9。
这时我们可以用WaitGroup来同步goroutineWaitGroup 等待所有任务退出主程序再退出,在每个goroutine完成后需调用Done()

package main

import (
    "fmt"
    "sync"
)

func RunLoop(){

    for i := 0; i < 10; i++ {
        fmt.Printf("%d ", i)
    }
}

func main(){


    var wg sync.WaitGroup
    wg.Add(1)

    go func() { //开启goroutine

        defer wg.Done()
        RunLoop()
    }()

    RunLoop()

    wg.Wait()
}

这样子就可以打印正常了

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 

资源竞争

在并发的过程中就会涉及到资源竞争的问题,多个并发操作同一个资源从而导致没有给出正确的结果。下面直接上代码

package main

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

var counter int
var wg sync.WaitGroup

func CounterAdd(){

    defer wg.Done()

    for i := 0; i < 2; i++ {

        value := counter

        //退出当前goroutine,并放回队列中
        runtime.Gosched()

        value ++

        counter = value
    }
}

func main(){

    wg.Add(2)

    go CounterAdd()
    go CounterAdd()

    wg.Wait()

    fmt.Println("Counter:", counter)
}

这时就产生了资源竞争的问题,输出结果有可能会输出 2、3、4,但是只有4这个结果才是正确的。
Go语言中有一个工具(-race),可以用来检测竞争状态,因为有时候竞争状态看起来并不那么明显。

go run  -race goroutine.go

WARNING: DATA RACE
Read at 0x000001211840 by goroutine 7:
main.CounterAdd()
/Users/justin910/Documents/Go/练习/goroutine.go:18 +0x6f

Previous write at 0x000001211840 by goroutine 6:
main.CounterAdd()
/Users/justin910/Documents/Go/练习/goroutine.go:25 +0x90

Goroutine 7 (running) created at:
main.main()
/Users/justin910/Documents/Go/练习/goroutine.go:34 +0x77

Goroutine 6 (finished) created at:
main.main()
/Users/justin910/Documents/Go/练习/goroutine.go:33 +0x5f
==================
Counter: 4
Found 1 data race(s)
exit status 66

根据上面的错误提示,可以查到是哪个goroutine引发了数据竞争,以及那几行代码有冲突。

sync.Mutex互斥锁

我们可以用系统sync包中提供的互斥锁来解决这一问题,保证同一时间最多只有一个goroutine访问该共享资源。

package main

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

var counter int
var wg sync.WaitGroup
var mutex sync.Mutex

func CounterAdd(){

    defer wg.Done()

    for i := 0; i < 2; i++ {

        mutex.Lock()
        value := counter

        //退出当前goroutine,并放回队列中
        runtime.Gosched()

        value ++

        counter = value
        mutex.Unlock()
    }
}

func main(){

    wg.Add(2)

    go CounterAdd()
    go CounterAdd()

    wg.Wait()

    fmt.Println("Counter:", counter)
}

加上互斥锁以后就能有效的保证共享资源的正确性。

总结

以上就是对于Go语言goroutine的介绍和使用,欢迎大家指出不足,相互交流。


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:Justin910

查看原文:Golang Goroutine 初识

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

986 次点击  ∙  1 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传