ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Go之组件学习-channel(concurrency篇)

2022-02-04 10:59:28  阅读:156  来源: 互联网

标签:ch func fmt goroutine go concurrency Go channel


文章目录

导语:

最近在学习关于go语言的concurrency的channel模块,就看到了ardan labs里面的一些例子,促进理解channel一些原理和使用

一、channel的定义

Channels allow goroutines to communicate with each other through the use of signaling semantics. Channels accomplish this signaling through the use of sending/receiving data or by identifying state changes on individual channels. Don't architect software with the idea of channels being a queue, focus on signaling and the semantics that simplify the orchestration required.

通道允许goroutine通过使用信令语义相互通信。信道通过使用发送/接收数据或识别单个信道上的状态变化来完成该信令。不要以通道是队列的想法来构建软件,而应关注简化所需编排的信令和语义。

二、channel的使用方式

在go中定义一个chan,即可开启通道模式

例如

	ch := make(chan int, 1)
	ch <- 1
	fmt.Println(<-ch)

以上的 ch<-1 就是将数据发送到channel中,而==<-ch==就是将数据发送出去。

这样可以实现channel管道接收和发送数据。

三、channel的一些场景

buffered(阻塞)

在这里插入图片描述

阻塞场景,并发场景,多数据的发送和多用户接收需要从channel中慢慢存和取,时间上延时性高,但是实现了高性能高效率传输。

unbuffered(非阻塞)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5EchdQfH-1643943060063)(/Users/jackthwu/Library/Application Support/typora-user-images/image-20211103163640288.png)]

非阻塞场景也是比较常见的,它实现了数据的快速发送和接收,常用于对等单个gorountine使用,一对一聊天室?低延时,但需要多个gorountine的建立,消耗大量性能。

四、channel的一些简单场景应用

1)父goroutine通过channel管道等待子goroutine的数据发送

// waitForResult: In this pattern, the parent goroutine waits for the child
// goroutine to finish some work to signal the result.
// 父goroutine等待信号结果
func waitForResult() {
	ch := make(chan string)

	go func() {
		time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
		ch <- "data"
		fmt.Println("child : sent signal")
	}()

	d := <-ch
	fmt.Println("parent : recv'd signal :", d)

	time.Sleep(time.Second)
	fmt.Println("-------------------------------------------------")
}

2)父goroutine发出100份信号,子goroutine一个pool池将等待信号接收

// pooling: In this pattern, the parent goroutine signals 100 pieces of work
// to a pool of child goroutines waiting for work to perform.
//父goroutine发出100份信号,子goroutine池将等待并工作
func pooling() {
	ch := make(chan string)
	//设置可以执行的最大CPU数量,指的是线程
	g := runtime.GOMAXPROCS(0)
	fmt.Println("====",g)
	for c := 0; c < g; c++ {
		go func(child int) {
			fmt.Println("!!!!!1")
			for d := range ch {
				fmt.Printf("child %d : recv'd signal : %s\n", child, d)
			}
			fmt.Printf("child %d : recv'd shutdown signal\n", child)
		}(c)
	}

	const work = 100
	for w := 0; w < work; w++ {
		ch <- "data" + strconv.Itoa(w)
		fmt.Println("parent : sent signal :", w)
	}

	close(ch)
	fmt.Println("parent : sent shutdown signal")

	time.Sleep(time.Second)
	fmt.Println("-------------------------------------------------")
}

3)使用channel管道模拟两个人网球比赛

// Sample program to show how to use an unbuffered channel to
// simulate a game of tennis between two goroutines.
//两个goroutines之间模拟网球比赛。
package main

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

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

func main() {

	// Create an unbuffered channel.
	court := make(chan int)

	// wg is used to manage concurrency.
	var wg sync.WaitGroup
	wg.Add(2)

	// Launch two players.
	go func() {
		player("Serena", court)
		wg.Done()
	}()

	go func() {
		player("Venus", court)
		wg.Done()
	}()

	// 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) {
	for {

		// Wait for the ball to be hit back to us.
		ball, wd := <-court
		if !wd {

			// 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", name)

			// 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
	}
}


五、channel 一些禁止项

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0dM29WA9-1643943060064)(/Users/jackthwu/Library/Application Support/typora-user-images/image-20211103164453129.png)]

在数据发送和接收这两种方式里,在channel管道关闭后,也有一些禁止项

比如说

管道closed后,不允许在发送数据,如果在发送数据会产生panic报错。

	ch := make(chan int,2)
	ch <- 1 //发送1到管道ch
	fmt.Println(<-ch)//接收管道的数据1
	close(ch)//关闭管道
	ch <- 2 //发送管道报错,已经关闭管道顾不可再发送,panic
	fmt.Println(<-ch)

以上代码将会报panic: send on closed channel错误

经过测试,改成以下代码印证了这个禁止项

	ch := make(chan int,2)
	ch <- 1//发送1到管道ch
	ch <- 2//发送2到管道ch
	fmt.Println(<-ch)//接收管道的数据1
	close(ch)
	fmt.Println(<-ch)//接收管道的数据2

文章借鉴

  • ardan labs go training - github web adress “https://github.com/ardanlabs/gotraining”

标签:ch,func,fmt,goroutine,go,concurrency,Go,channel
来源: https://blog.csdn.net/qq_41903105/article/details/122781651

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有