公司搞了午间技术par,本周我讲的主题是关于无缓冲通道channel是否会发生阻塞,并进行了验证。

go语言中channel分为无缓冲通道和有缓冲通道两种

channel提供了一种在goroutine之间共享数据的简单方法。

废话少说借用William Kennedy 打球的例子,代码如下:

C:\Users\Administrator>go version   版本信息如下:
go version go1.9 windows/amd64

// This sample program demonstrates how to use an unbuffered
// channel to simulate a game of tennis between two goroutines.
package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

// wg is used to wait for the program to finish.
var wg sync.WaitGroup

func init() {
	rand.Seed(time.Now().UnixNano())
}

// main is the entry point for all Go programs.
func main() {
	// Create an unbuffered channel.
	court := make(chan int)

	// Add a count of two, one for each goroutine.
	wg.Add(2)

	// Launch two players.
	go player("Nadal", court)
	go player("Djokovic", court)

	// Start the set.
	court <- 1

	// Wait for the game to finish.
	wg.Wait()
}

// player simulates a person playing the game of tennis.
func player(name string, court chan int) {
	// Schedule the call to Done to tell main we are done.
	defer wg.Done()

	for {
		// Wait for the ball to be hit back to us.
		ball, ok := <-court
		if !ok {
			// If the channel was closed we won.
			fmt.Printf("Player %s Won\n", name)
			return
		}

		// Pick a random number and see if we miss the ball.
		n := rand.Intn(100)
		if n%13 == 0 {
			fmt.Printf("Player %s Missed\n", ``)

			// Close the channel to signal we lost.
			close(court)
			return
		}

		// Display and then increment the hit count by one.
		fmt.Printf("Player %s Hit %d\n", name, ball)
		ball++

		// Hit the ball back to the opposing player.
		court <- ball
	}
} 

 为了验证无缓冲通道是否会阻塞,注释go player("Djokovic", court)  且将wg.Add(1)修改成1,因为只有1个go routinue要运行,如果不阻塞程序将可以正常运行,修改后的程序如下

// This sample program demonstrates how to use an unbuffered
// channel to simulate a game of tennis between two goroutines.
package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

// wg is used to wait for the program to finish.
var wg sync.WaitGroup

func init() {
	rand.Seed(time.Now().UnixNano())
}

// main is the entry point for all Go programs.
func main() {
	// Create an unbuffered channel.
	court := make(chan int)

	// Add a count of two, one for each goroutine.
	wg.Add(2)

	// Launch two players.
	go player("Nadal", court)
	//go player("Djokovic", court)

	// Start the set.
	court <- 1

	// Wait for the game to finish.
	wg.Wait()
}

// player simulates a person playing the game of tennis.
func player(name string, court chan int) {
	// Schedule the call to Done to tell main we are done.
	defer wg.Done()

	for {
		// Wait for the ball to be hit back to us.
		ball, ok := <-court
		if !ok {
			// If the channel was closed we won.
			fmt.Printf("Player %s Won\n", name)
			return
		}

		// Pick a random number and see if we miss the ball.
		n := rand.Intn(100)
		if n%13 == 0 {
			fmt.Printf("Player %s Missed\n", ``)

			// Close the channel to signal we lost.
			close(court)
			return
		}

		// Display and then increment the hit count by one.
		fmt.Printf("Player %s Hit %d\n", name, ball)
		ball++

		// Hit the ball back to the opposing player.
		court <- ball
	}
}

 运行结果:

Player Nadal Hit 1
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0x56e00c)
	D:/Program Files/GO/src/runtime/sema.go:56 +0x40
sync.(*WaitGroup).Wait(0x56e000)
	D:/Program Files/GO/src/sync/waitgroup.go:131 +0x79

再次修改程序将court := make(chan int) 改成court := make(chan int,1)有缓冲

// This sample program demonstrates how to use an unbuffered
// channel to simulate a game of tennis between two goroutines.
package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

// wg is used to wait for the program to finish.
var wg sync.WaitGroup

func init() {
	rand.Seed(time.Now().UnixNano())
}

// main is the entry point for all Go programs.
func main() {
	// Create an unbuffered channel.
	court := make(chan int,1)

	// Add a count of two, one for each goroutine.
	wg.Add(1)

	// Launch two players.
	go player("Nadal", court)
	//go player("Djokovic", court)

	// Start the set.
	court <- 1

	// Wait for the game to finish.
	wg.Wait()
}

// player simulates a person playing the game of tennis.
func player(name string, court chan int) {
	// Schedule the call to Done to tell main we are done.
	defer wg.Done()

	for {
		// Wait for the ball to be hit back to us.
		ball, ok := <-court
		if !ok {
			// If the channel was closed we won.
			fmt.Printf("Player %s Won\n", name)
			return
		}

		// Pick a random number and see if we miss the ball.
		n := rand.Intn(100)
		if n%13 == 0 {
			fmt.Printf("Player %s Missed\n", ``)

			// Close the channel to signal we lost.
			close(court)
			return
		}

		// Display and then increment the hit count by one.
		fmt.Printf("Player %s Hit %d\n", name, ball)
		ball++

		// Hit the ball back to the opposing player.
		court <- ball
	}
}

运行结果:

Player Nadal Hit 1
Player Nadal Hit 2
Player Nadal Hit 3
Player Nadal Hit 4
Player  Missed

结论:

无缓冲的通道会发生阻塞

golang channel无缓冲通道会发生阻塞的验证的更多相关文章

  1. Golang并发编程有缓冲通道和无缓冲通道(channel)

    无缓冲通道 是指在接收前没有能力保存任何值得通道.这种类型的通道要求发送goroutine和接收goroutine同时准备好,才能完成发送和接收操作.如果两个goroutine没有同时准备好,通道会导 ...

  2. [GO]无缓冲通道(unbuffered channel)

    无缓冲通道(unbuffered channel)是指在接收前没有能力保存任何值的通道,在之前的例子中使用的都是无缓冲通道,需要注意的是,对于无缓冲通道而言,不管是往通道里写数据还是从通道里读数据,都 ...

  3. [Go] golang无缓冲通道实现工作池控制并发

    展示如何使用无缓冲的通道创建一个goroutine池,控制并发频率1.无缓冲通道保证了两个goroutine之间的数据交换2.当所有的goroutine都忙的时候,能够及时通过通道告知调用者3.无缓冲 ...

  4. golang中为何在同一个goroutine中使用无缓冲通道会导致死锁

    package main import "fmt" func main() { /* 以下程序会导致死锁 c := make(chan int) c <- 10 n1 := ...

  5. Go语言的通道(1)-无缓冲通道

    前言: 上文中我们采用了[原子函数]已经[共享锁]两种方式分别对多个goroutine进行了同步,但是在go语言中提供了另一种更好的方式,那就是使用通道(Channel). 一.通道是什么? 其实无论 ...

  6. go无缓冲通道

    package main import ( "fmt" "math/rand" "sync" "time" ) //wg ...

  7. Go语言有缓冲和无缓冲通道实现样例

    感觉可以,但不好用. 应该有封装程序更高的包包吧. package main import ( "math/rand" "fmt" "time&quo ...

  8. golang的缓冲channel和无缓冲channel的区别

    话说golang的channel同步的定义真是让人无力吐槽,码农的用户体验就这么难搞么,超耐磨阿,无缓冲和缓冲居然有这么大区别....靠 转载一段网上的资料 --------------------- ...

  9. go之无缓冲channel(通道)和有缓冲channel(通道)

    channel我们先来看一下通道的解释:channel是Go语言中的一个核心类型,可以把它看成管道.并发核心单元通过它就可以发送或者接收数据进行通讯,这在一定程度上又进一步降低了编程的难度.chann ...

随机推荐

  1. SSM整合学习笔记

    对学习Spring+Spring MVC+Mybatis过程中出现的问题解决办法汇总 出现的问题 1.pom.xml报错 右键项目->maven->update project 因此每次更 ...

  2. (转)centos7安装telnet服务

    场景:在进行Telnet测试时候,发现无法连接,所以还得把这个软件也安装了 1 CentOS7.0 telnet-server 启动的问题 解决方法:   先检查CentOS7.0是否已经安装以下两个 ...

  3. 【JAVASCRIPT】React学习- 数据流(组件通信)

    摘要 react 学习包括几个部分: 文本渲染 JSX 语法 组件化思想 数据流 一 组件通信如何实现 父子组件之间不存在继承关系 1.1 父=>子通信 父组件可以通过 this.refs.xx ...

  4. 从Ubunt的安装到hadoop集群的搭建

    一.相关基础配置 1.网络设置 a.调整VMnet8这块网卡网关 b.在VMware[编辑]->[虚拟网络编辑器]对VMnet8进线[NAT 设置] c.调整[DHCP 设置]中的起始IP地址 ...

  5. github 或者gitlab 设置添加SSH

    克隆项目二种方式: 1. 使用https url克隆,   复制https url 然后到 git clone https-url 2.使用 SSH url 克隆却需要在克隆之前先配置和添加好 SSH ...

  6. 调皮的QQ音乐API:修复无法获取歌单

    上一篇完整版:http://www.cnblogs.com/TwilightLemon/p/7076938.html QQ音乐的API真是太调皮了,获取歌单的API又更换了好多次,喵喵喵 旧版API( ...

  7. Samba服务部署

    Samba,是种用来让UNIX系列的操作系统与微软Windows操作系统的SMB/CIFS(Server Message Block/Common Internet File System)网络协议做 ...

  8. CodeForces 816B Karen and Coffee(前缀和,大量查询)

    CodeForces 816B Karen and Coffee(前缀和,大量查询) Description Karen, a coffee aficionado, wants to know the ...

  9. 简陋的 ASP.NET CORE 单页Web应用程序“框架”

    我对ASP.NET CORE了解不多,不知道是不是重复造轮子,也或者什么也不是,这个Demo是这样的: 1.非常简单或者说原始:2.将单页Web应用增加了一个页(Page)概念(相当于MVC的 Vie ...

  10. 又见angular----步一步做一个angular4小项目

    这两天看了看angular4的文档,发现他和angular1.X的差别真的是太大了,官方给出的那个管理英雄的Demo是一个非常好的入门项目,这里给出一个管理个人计划的小项目,从头至尾一步一步讲解如何去 ...