Go语言为并发编程而内置的上层API基于CSP(communication sequential processes,顺序通信进程)模型。这就意味着显式锁都是可以避免的,比如资源竞争,比如多个进程同时获取文件资源需要修改,首先拿到资源的进程加上锁,等修改完之后把锁去掉,然后再给下一个进程来进行修改,只有这样才不会出现数据不一致。但是go语言不是通过锁的方式,是通过通信的方式,安全的通道发送和接收数据以实现同步,这就大大的简化了并发编程的编写。

一般情况下,一个普通的计算机跑十几二十几个线程就有点负载过大,但是同样这台机器却可以让成千甚至过万哥goroutine进行资源竞争

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

创建goroutine

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

在并发编程里,我们通常想将一个过程切分成几块,然后让每个goroutine各自负责一块工作。当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine,新的goroutine会用go语句来创建,至于主和子谁先执行,由系统决定。重点:主协程退出了,其它子协程也要跟着退出;其次,主协程先退出导致子协程没来得及调用

package main

import (
    "fmt"
    "time"
)

func newTask() {
    for {
        fmt.Println("this is a newTask")
        time.Sleep(time.Second) //延时1s
    }
}

func main() { //可以理解为主 goroutine

    go newTask() //新建一个协程, 新建一个任务

    for {
        fmt.Println("this is a main goroutine")
        time.Sleep(time.Second) //延时1s
    }
    //newTask()  子协程(goroutine)如果放在这会执行不到,因为程序都是单业务。for循环是一个任务,下面执行不到

    //go newTask() 但是前面加上go关键字,放到下面也没法执行
}
this is a main goroutine
this is a newTask
this is a main goroutine
this is a newTask
this is a main goroutine
this is a newTask
this is a main goroutine
this is a newTask

主协程退出了,其它子协程也要跟着退出。

package main

import (
    "fmt"
    "time"
)

//主协程退出了,其它子协程也要跟着退出
func main() {

    go func() {
        i := 0
        for {
            i++
            fmt.Println("子协程 i = ", i)
            time.Sleep(time.Second)
        }

    }()

    i := 0
    for {
        i++
        fmt.Println("main i = ", i)
        time.Sleep(time.Second)

        if i == 2 {
            break
        }
    }

}
main i =  1
子协程 i =  1
main i =  2
子协程 i =  2

主协程先退出导致子协程没来得及调用

package main

import (
    "fmt"
    "time"
)

//主协程退出了,其它子协程也要跟着退出
func main() {

    go func() {
        i := 0
        for {
            i++
            fmt.Println("子协程 i = ", i)
            time.Sleep(time.Second)
        }

    }()

}
//执行代码并无任何输出,因为主协程先执行完退出