gorountine与 channel的关系

64 阅读3分钟

重新温习当初的课程,发现还是有些不太懂的地方。 查了下资料大概如下所述。

Go语言中并发用两种方式来实现。

  • goroutine和channel,其支持“顺序进程通信”(communicating sequential processes)或被简称为CSP。CSP是一个现代的并发编程模型,在这种编程模型中值会在不同的运行实例(goroutine)中传递,尽管大多数情况下被限制在单一实例中。
  • 传统的并发模型,多线程共享内存(基于共享变量的并发),就是传统并发编程的加锁。

goroutine

goroutine是一个轻量级的执行线程(又称协程),它与线程的区别是线程是操作系统中对于一个独立运行实例的描述,不同的操作系统中,线程的实现也不尽相同;对于goroutine,操作系统并不知道它的存在,goroutine的调度是Go语言的运行时进行管理的。启动线程虽然比进程使用的资源少,但依然需要上下文切换等大量工作,Go语言有自己的调度器,许多goroutine的数据都是共享的,因此goroutine之间的切换会快很多,启动goroutine所耗费的资源也很少。

func Info(name string)  {
    for i := 0; i < 3; i++ {
        fmt.Println(name + ":" + strconv.Itoa(i))
    }
}

func main()  {
    Info("info")

    go Info("goroutine1")

    go func(name string) {
        fmt.Println(name)
    }("goroutine2")

    var input string
    fmt.Scanln(&input)
    fmt.Println("done")
}

channel

channel被称为通道,是连接并发goroutine的管道,可以从一个goroutine向通道发送值,并在另一个goroutine中接收到这些值。每个channel都有一个特殊的类型,也就是channel可发送数据的类型。一个可以发送int类型数据的channel一般写为chan int。

一个channel有发送和接收两个主要操作,都是通信行为。一个发送语句将一个值从一个goroutine通过channel发送到另一个执行接收操作的goroutine。发送和接收两个操作都是用<-运算符。在发送语句中,<-运算符分割channel和要发送的值;在接收语句中,<-运算符写在channel对象之前,一个不使用接收结果的接收操作也是合法的。

channel的发送操作将导致发送者goroutine阻塞,直到另一个goroutine在相同的channel上执行接收操作,当发送的值通过channel成功传输之后,两个goroutine可以继续执行后面的语句。反之,如果接收操作先发生,那么接收者goroutine也将阻塞,直到有另一个goroutine在相同的Channels上执行发送操作。

func Info(i int, ch chan string)  {
    msg := "数据" + strconv.Itoa(i)
    ch <- msg
}

func main()  {
    chs := make([]chan string, 3)
    for i := 0; i < 3; i++ {
        chs[i] = make(chan string)
        go Info(i, chs[i])
    }

    for num, ch := range chs {
        msg := <- ch
        fmt.Println(num, msg)
    }

    fmt.Println("Done")
}

select

Go语言的select的功能和select、poll、epoll相似,就是监听IO操作,当IO操作发生时,触发响应的动作。select语句的用法和switch相似,也会有几个case和default分支,每一个case代表一个通信操作(在某个channel上进行发送或者接收)并且会包含一些语句组成一个语句块。