Goroutines和Channels

原文链接 https://golangbot.com/goroutines/

Goroutines

Goroutines 可以被认为是多个函数或方法同时允许。可以认为是一个轻量级的线程。与线程的花费相比是非常小的。

与线程相比的优势

  • Goroutines 非常的轻量级,只需要几kb的内存分配 并且是可以根据需要动态可伸缩的。而线程的内存分配大小是固定的
  • Goroutines 可以多路复用到几个OS线程中。可能只有一个线程对应到很多歌Goroutines.如果有任何一个Goroutine等待了 比如说需要用户输入 那么另外一个OS线程就会被创建 然后剩下的Goroutines 就会被移动到新的OS线程中被执行
  • Goroutines使用channels沟通。channels被设计在多个Goroutines共享内存时 防止竞态的发生。channels可以被认为是Goroutines的沟通管道

开始运行一个Goroutine

例子

package main

import (
	"fmt"
)

func hello() {
	fmt.Println("Hello world goroutine")
}
func main() {
	go hello()
	
	//time.Sleep(1 * time.Second)
    //fmt.Println("main function")

	fmt.Println("main function")
}

执行这段程序之后 不会有任何输出

  • 当执行一个Goroutine,goroutine会立即返回并执行下一段代码 以至于任何goroutine的返回值都会被忽略掉
  • 当主Goroutine停止之后 其它任何的Goroutie也都会被终止

channels

  • channels可以认为是Goroutines的沟通通道。

例子

package main
import (
	"fmt"
)

func hello(done chan bool){
	fmt.Println("hello goroutine")
	done <- true
}

func main(){
	done := make(chan bool)

	go hello(done)

	<-done

	fmt.Println("main function")
}
  • <-done 这行代码会阻止程序继续往下运行 直到Goroutine写了数据到这个channel之中 然后channel里面收到数据之后 程序会继续往下进行
  • 如果需要等待多个Goroutine 则需要发送多个值到channel 也相应的要有多个相对应的接收channel

Deadlock

  • 如果从一个Goroutine通过通道发送了数据 那么被认为会有另外一个Goroutine接收相对应的数据 如果没有的话就会产生paninc 也就发生了死锁

  • 相似的 如果Goroutine从一个channel钟等待数据 那么应该会有另外一个Goroutine通过channle发送数据 否则的话也会发生paninc

例子

package main

func main() {  
    ch := make(chan int)
    ch <- 5
}
  • fatal error: all goroutines are asleep - deadlock!

Unidirectional channels(单向channel)

例子1

package main

import "fmt"

func sendData(sendch chan<- int) {  
    sendch <- 10
}

func main() {  
    sendch := make(chan<- int)  //只运行向channel发送数据
    
    go sendData(sendch)
    fmt.Println(<-sendch)   //这里从channel钟接收数据 则报错
}

例子2

//这里定义了一个只往channel发送的类型
func sendData(sendch chan<- int) {
	sendch <- 10    
}

func main() {
	chnl := make(chan int)
	go sendData(chnl)
	fmt.Println(<-chnl)
}

Closing channels and for range loops on channels

  • 发送者是可以关闭channel 来通知接收者没有数据要往这个channel中发送了
  • 接收者可以使用另外一个变量来检测是否channel已经关闭了 v, ok := <- ch

例子

package main

import (
	"fmt"
)

func producer(c chan int){
	for i:=0; i < 10; i++{
		c <- i
	}

	close(c)
}

func main() {
	ch := make(chan int)

	//for{
	//	v,ok := <-ch
	//	if ok == false{
	//		break
	//	}
	//
	//	fmt.Println("Received ",v,ok)
	//}

	for v := range ch{
		fmt.Println("Received ",v)
	}
}
原文地址:https://www.cnblogs.com/alin-qu/p/8545553.html