全栈编程

Balance $ 2,317
Item Sold 1230
文章作者: 全栈编程@luboke.com
版权声明: 本文章为go语言体系课视频教程配套电子书,版权归 全栈编程@luboke.com所有,欢迎免费学习,转载必须注明出处!但禁止任何商业用途,否则将受到法律制裁!

  死锁(deadlock)

当channel的某一端(sender/receiver)期待另一端的(receiver/sender)操作,另一端正好在期待本端的操作时,也就是说两端都因为对方而使得自己当前处于阻塞状态,这时将会出现死锁问题。

更通俗地说,只要所有goroutine都被阻塞,就会出现死锁

比如,在main函数中,它有一个默认的goroutine,如果在此goroutine中创建一个unbuffered channel,并在main goroutine中向此channel中发送数据并直接receive数据,将会出现死锁

package main

import (
	"fmt"
)

func main (){
	goo(32)
}

func goo(s int) {
	counter := make(chan int)
	counter <- s
	fmt.Println(<-counter)
}

在上面的示例中,向unbuffered channel中send数据的操作counter <- s是在main goroutine中进行的,从此channel中recv的操作<-counter也是在main goroutine中进行的。send的时候会直接阻塞main goroutine,使得recv操作无法被执行,go将探测到此问题,并报错.

要修复此问题,只需将send操作放在另一个goroutine中执行即可

package main

import (
	"fmt"
)

func main() {
	goo(32)
}

func goo(s int) {
	counter := make(chan int)
	go func() {
		counter <- s
	}()
	fmt.Println(<-counter)
}

 

或者,将counter设置为一个容量为1的buffered channel

这样放完一个数据后send不会阻塞(被recv之前放第二个数据才会阻塞),可以执行到recv操作

package main

import (
	"fmt"
)

func main (){
	goo(32)
}

func goo(s int) {

	//将counter设置为一个容量为1的buffered channel,这样放完一个数据后send不会阻塞(被recv之前放第二个数据才会阻塞),可以执行到recv操作。
	
	counter := make(chan int,1)
	counter <- s
	fmt.Println(<-counter)
}

buffered channel 实现fibonacci、for ...range channel

package main

import "fmt"

func main()  {
	//Range 和 Close
	//上面这个例子中,我们需要读取两次 c,这样不是很方便,Go 考虑到了这一点,所以也可以通过 range,像操作 slice 或者 map 一样操作缓存类型的 channel

	channel3 := make(chan int, 10)
	go fibonacci(cap(channel3), channel3)
	for i := range channel3 {
		fmt.Println(i)
	}

	fibonacci2(10)
	//for i := range c 能够不断的读取 channel 里面的数据,直到该 channel 被显式的关闭。上面代码我们看到可以显式的关闭 channel,生产者通过内置函数 close 关闭 channel。关闭 channel 之后就无法再发送任何数据了,在消费方可以通过语法 v, ok := <-ch 测试 channel 是否被关闭。如果 ok 返回 false,那么说明 channel 已经没有任何数据并且已经被关闭。
	//记住应该在生产者的地方关闭 channel,而不是消费的地方去关闭它,这样容易引起 panic
	//另外记住一点的就是 channel 不像文件之类的,不需要经常去关闭,只有当你确实没有任何发送数据了,或者你想显式的结束 range 循环之类的
}

func fibonacci(n int, c chan int) {
	x, y := 1, 1
	for i := 0; i < n; i++ {
		c <- x
		x, y = y, x + y
	}
	close(c)
}
func fibonacci2(n int) {
	x, y := 1, 1
	for i := 0; i < n; i++ {
		fmt.Println(x)
		x, y = y, x + y
	}
}

 

文章作者: 全栈编程@luboke.com
版权声明: 本文章为go语言体系课视频教程配套电子书,版权归 全栈编程@luboke.com所有,欢迎免费学习,转载必须注明出处!但禁止任何商业用途,否则将受到法律制裁!
copyright © 2020 全栈编程@luboke.com