公司搞了午间技术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. nyoj_762:第k个互质数

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=762 直接给代码好了,容斥原理具体看<组合数学> #include<bi ...

  2. maven - 引用本地jar,进行jar包移动

    背景: 项目为maven工程,部分jar需要需用项目单独修改的本地jar包. 配置好scope后发现构建后引用的jar没有移动到对应的目录,百度后发现需要配置以下依赖 <plugin> & ...

  3. BI服务器配置与客户端情况

    1. BI描述 FineBI是一款纯B/S端的商业智能分析服务平台:支持通过web应用服务器将其部署在服务器上,提供企业云服务器.用户端只需要使用一个浏览器即可进行服务平台的访问和使用.因此在配置使用 ...

  4. Unity strip engine code可能会使程序崩溃

    最近正在做新大厅的红包推荐口令快速领金币入口拍卖行之类的功能,同事把我的捕鱼整合到他的项目中时出现了闪退的问题,经排查是因为strip engine code选项. Strip engine code ...

  5. 用Node.JS+MongoDB搭建个人博客(安装环境)(一)

    Node.JS是什么? Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境. Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效. Nod ...

  6. python开发部署时新增数据库中表的方法

    在项目版本让运维部署时,涉及到数据库表的增加问题,想了一下,可以有四种方法 1.使用SQLAlchemy的db.create_all()方法 # -*- coding:utf-8 -*- from f ...

  7. php+sqlserver实现分页效果

    找了一些实现的代码,都或多或少有点问题. 主要问题在于: 在进行一页数据查询时的sql语句格式问题, 开始尝试使用limit关键字查询,错误,limit用于mysql: 接着使用ROWNUM.row_ ...

  8. ubuntu上安装apache2+mysql+php5-fpm(PHP5 - FastCGI Process Manager)

    1: 安装mysql apt-get install mysql-server mysql-client 安装过程中会被问到设置mysql root的密码     New password for t ...

  9. 36. leetcode 415. Add Strings

    415. Add Strings Given two non-negative integers num1 and num2 represented as string, return the sum ...

  10. SpringBoot初识(一)

    一.什么是SpringBoot 最近几年,微服务的概念越来越火.而相信大家在搜索微服务时,映入眼帘的首先就是SpringBoot以及SpringCloud.SpringCloud提供的一套完整的微服务 ...