公司搞了午间技术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. SQL Server2008 安装及概述

    最近在学习SQL Server 数据库,用的版本是2008 R2的版本,如下图所示,本人学习时间不长,写这篇文章一是为了锻炼自己加深印象,二也可以与和诸多朋友进行交流以及得到大家的指教. 安装教程网上 ...

  2. java内存区域——深入理解JVM读书笔记

    本内容由<深入理解java虚拟机>的部分读书笔记整理而成,本读者计划连载. 通过如下图和文字介绍来了解几个运行时数据区的概念. 方法区:它是各个线程共享的区域,用于内存已被VM加载的类信息 ...

  3. 使用Dubbo、JSF等RPC框架时,对于异常的处理

    无论是Dubbo还是JSF等RPC框架,一般都会把接口分为2部分: 1,服务端(provider) 2,客户端(consumer) 由于,客户端与服务端可能不在同一个应用中,所以客户端一般在调用服务端 ...

  4. 【SpringMVC】静态资源访问的问题

    在项目中经常会用到一些静态的资源,而一般我们在配置SpringMVC时会让SpringMVC接管所有的请求(包括静态资源的访问), 那么我们怎样才能最简单的来配置静态资源的访问呢? 一,在web.xm ...

  5. JavaWeb学习归档(一) - HTTP协议总结

    版权声明:本文为博主原创文章,未经博主允许不得转载. 本文转载自我的个人博客:http://www.codingme.net/post/java-web-01 HTTP协议简介 超文本传输协议(HTT ...

  6. python关于list的三个内置函数filter(), map(), reduce()

    ''' Python --version :Python 2.7.11 Quote : https://docs.python.org/2/tutorial/datastructures.html#m ...

  7. 使用jquery获取url及url参数的方法

    使用jquery获取url以及使用jquery获取url参数是我们经常要用到的操作 1.jquery获取url很简单,代码如下: window.location.href; 其实只是用到了javasc ...

  8. Modular javascript(javascript模块化编程)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. 求m区间内的最小值

    洛谷P1440 求m区间内的最小值 ............................................................................... 以上 ...

  10. 超超超简单的bfs——POJ-3278

    Catch That Cow Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 89836   Accepted: 28175 ...