go routine channel select

2023-05-16

一、go routine channel

package main

import (
	"fmt"
	"time"
)

func worker(id int, c chan int) {
	for n := range c {//读取channel
		fmt.Printf("Worker %d received %c\n",
			id, n)
	}
}

func createWorker(id int) chan<- int {
	c := make(chan int)
	go worker(id, c)//routine,可以理解为新开线程
	return c
}

func chanDemo() {
	var channels [10]chan<- int
	for i := 0; i < 10; i++ {
		channels[i] = createWorker(i)
	}

	for i := 0; i < 10; i++ {
		channels[i] <- 'a' + i//向channel中写入数据
	}

	for i := 0; i < 10; i++ {
		channels[i] <- 'A' + i
	}

	time.Sleep(time.Second)//主线程也是个runtine
}

func bufferedChannel() {
	c := make(chan int, 3)
	go worker(0, c)
	c <- 'a'
	c <- 'b'
	c <- 'c'//如果没有人接收,可以在缓冲区存放3个,发送第四个时候会阻塞;如果make(chan int),如果没有人接收,在发送第二个时候,就会阻塞。
	c <- 'd'
	time.Sleep(time.Millisecond)
}

func channelClose() {
	c := make(chan int)
	go worker(0, c)
	c <- 'a'
	c <- 'b'
	c <- 'c'
	c <- 'd'
	close(c)//关闭channel后不能发送和接收数据了
	time.Sleep(time.Second * 20)
}

func main() {
	fmt.Println("Channel as first-class citizen")
	chanDemo()
	//fmt.Println("Buffered channel")
	//bufferedChannel()
	//fmt.Println("Channel close and range")
	//channelClose()
}

输出:

Worker 0 received a
Worker 1 received b
Worker 2 received c
Worker 3 received d
Worker 4 received e
Worker 4 received E
Worker 0 received A
Worker 7 received h
Worker 2 received C
Worker 9 received j
Worker 1 received B
Worker 6 received g
Worker 3 received D
Worker 8 received i
Worker 5 received f
Worker 5 received F
Worker 8 received I
Worker 6 received G
Worker 7 received H
Worker 9 received J
go runtine可以理解为新开个线程,不过实际上很多runtime可以运行在一个线程中,由go虚拟机去调度。

go channel是为了不同go runtine间通信而设置的。

1、发送channel后,只能在其他runtine中接收到channel后,才会继续执行下条语句,否则在发送channel时睡眠等待

2、如果是接收channel,如果没有发送者,则会一直等待,直到发送channel。

package main

import (
	"fmt"
	"time"
)

func worker(id int, c chan int) {
	time.Sleep(time.Second * 5)
	for n := range c {
		fmt.Printf("Worker %d received %c\n",
			id, n)
	}
}

func createWorker(id int) chan<- int {
	c := make(chan int)
	go worker(id, c)
	return c
}


func channelClose() {
	c := make(chan int)
	go worker(0, c)
	c <- 'a'//发送channel后,只能在其他runtine中接收到channel后,才会继续执行下条语句,否则在发送channel时睡眠等待
	fmt.Println("run here")
	c <- 'b'
	c <- 'c'
	c <- 'd'
	time.Sleep(time.Second * 20)
}

func main() {
	fmt.Println("Channel close and range")
	channelClose()
}

先睡眠等待5秒后,才打印run here。

 

二、channel完整例子

package main

import (
	"fmt"
)

func doWork(id int,
	w worker) {
	for n := range w.in {
		fmt.Printf("Worker %d received %c\n",
			id, n)
		w.done <- true
	}
}

type worker struct {
	in   chan int
	done chan bool
}

func createWorker(
	id int) worker {
	w := worker{
		in: make(chan int),
		done: make(chan bool),
	}
	go doWork(id, w)
	return w
}

func chanDemo() {

	var workers [10]worker
	for i := 0; i < 10; i++ {
		workers[i] = createWorker(i)
	}


	for i, worker := range workers {
		worker.in <- 'a' + i
	}

	for _, worker := range workers {
		<-worker.done
	}

	for i, worker := range workers {
		worker.in <- 'A' + i
	}

	for _, worker := range workers {
		<-worker.done
	}
}

func main() {
	chanDemo()
}

输出:

Worker 9 received j
Worker 8 received i
Worker 7 received h
Worker 0 received a
Worker 2 received c
Worker 1 received b
Worker 3 received d
Worker 5 received f
Worker 6 received g
Worker 4 received e
Worker 1 received B
Worker 0 received A
Worker 3 received D
Worker 2 received C
Worker 4 received E
Worker 5 received F
Worker 9 received J
Worker 8 received I
Worker 6 received G
Worker 7 received H

package main

import (
	"fmt"
)

func doWork(id int,
	w worker) {
	for n := range w.in {
		fmt.Printf("Worker %d received %c\n",
			id, n)
		w.done <- true//没有人接收,会卡在这句上,而马上又要发送channel,接收的语句还在发送channel后面,死锁
	}
}

type worker struct {
	in   chan int
	done chan bool
}

func createWorker(
	id int) worker {
	w := worker{
		in: make(chan int),
		done: make(chan bool),
	}
	go doWork(id, w)
	return w
}

func chanDemo() {

	var workers [10]worker
	for i := 0; i < 10; i++ {
		workers[i] = createWorker(i)
	}


	for i, worker := range workers {
		worker.in <- 'a' + i
	}

	for i, worker := range workers {
		worker.in <- 'A' + i
	}

	for _, worker := range workers {
		<-worker.done
		<-worker.done
	}
}

func main() {
	chanDemo()
}

输出:

Worker 8 received i
Worker 9 received j
Worker 1 received b
Worker 3 received d
Worker 5 received f

Worker 4 received e
Worker 6 received g
Worker 2 received c
Worker 0 received a
fatal error: all goroutines are asleep - deadlock!
 

三、select

package main

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

func generator() chan int {
	out := make(chan int)
	go func() {
		i := 0
		for {
			time.Sleep(time.Duration(rand.Intn(1500))* time.Millisecond)
			out <- i
			i++
		}
	}()
	return out
}

func main() {
	var c1 ,c2 = generator(), generator()
	var c3 chan int
	c3 = make(chan int)
	for {
		select {
		case n := <-c1:
			fmt.Println("Received from c1:", n)
		case n := <-c2:
			fmt.Println("Received from c2:", n)
		case c3 <- 1:
			fmt.Println("send c3:")
		}
	}


}

select和不加select有什么区别呢?

不加select:

如果接收时,没有人发送,会睡眠等待,如n := <-c1。如果发送,没有人接收,会睡眠等待如c3 <- 1。

加select:

如果接收时,没有人发送,会继续向下匹配,如n := <-c1。如果发送,没有人接收,会继续向下匹配如c3 <- 1。

如果全部没有匹配,会睡眠等待,直到有匹配项过来。如果有default,则走default,不会睡眠等待。

如果接收时,有人发送,匹配成功,进入case内语句执行后,继续下一轮匹配,如n := <-c1。

如果发送,有人接收,匹配成功,进入case内语句执行后,会继续向下匹配如c3 <- 1。

package main

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

func generator() chan int {
	out := make(chan int)
	go func() {
		i := 0
		for {
			time.Sleep(
				time.Duration(rand.Intn(1500)) *
					time.Millisecond)
			out <- i
			i++
		}
	}()
	return out
}

func worker(id int, c chan int) {
	for n := range c {
		time.Sleep(time.Second)
		fmt.Printf("Worker %d received %d\n",
			id, n)
	}
}

func createWorker(id int) chan<- int {
	c := make(chan int)
	go worker(id, c)
	return c
}

func main() {
	var c1, c2 = generator(), generator()
	var worker = createWorker(0)

	var values []int
	tm := time.After(10 * time.Second)
	for {
		var activeWorker chan<- int
		var activeValue int
		if len(values) > 0 {
			activeWorker = worker
			activeValue = values[0]
		}

		select {
		case n := <-c1:
			values = append(values, n)
			fmt.Println("set values:", values)
		case n := <-c2:
			values = append(values, n)
			fmt.Println("set values:", values)
		case activeWorker <- activeValue:
			values = values[1:]
			fmt.Println("get values:", values)
		case <-tm:
			fmt.Println("bye")
			return
		}
	}
}

输出:

//刚开始没有c1和c2没有接受到数据时,由于activeWorker是nil chan,所以此时会睡眠,但在select的时候直接跳过。如果所有case都不匹配,那么就睡眠了。

第一轮:---睡眠等待---

之后每次匹配所有项,如果c1和c2有人写,activeWorker有值并且读端正在等待读,则执行case;如果都不匹配,那么就睡眠等待直到匹配,再执行下一轮循环把数据拿出来。

第二轮:set values: [0] //从c1获取数据
第三轮:get values: [] //activeWorker有值,向其中写入数据,并且读端正在等待读,此时可写入数据,执行case语句

第四轮:---睡眠等待---
第五轮:set values: [0] //从c2获取数据
第六轮:set values: [0 1]

第七轮:---睡眠等待---
第八轮:set values: [0 1 1]

第九轮:---睡眠等待---
第十轮:set values: [0 1 1 2]

第十一轮:---睡眠等待---
Worker 0 received 0 //读端结束sleep,继续等待读状态,for n := range c {
第十二轮get values: [1 1 2] //activeWorker有值,向其中写入数据,并且读端正在等待读,此时可写入数据,执行case语句
set values: [1 1 2 2]
set values: [1 1 2 2 3]
Worker 0 received 0
get values: [1 2 2 3]
set values: [1 2 2 3 3]
set values: [1 2 2 3 3 4]
set values: [1 2 2 3 3 4 5]
Worker 0 received 1
get values: [2 2 3 3 4 5]
set values: [2 2 3 3 4 5 4]
set values: [2 2 3 3 4 5 4 5]
set values: [2 2 3 3 4 5 4 5 6]
set values: [2 2 3 3 4 5 4 5 6 6]
Worker 0 received 1
get values: [2 3 3 4 5 4 5 6 6]
set values: [2 3 3 4 5 4 5 6 6 7]
set values: [2 3 3 4 5 4 5 6 6 7 7]
Worker 0 received 2
get values: [3 3 4 5 4 5 6 6 7 7]
set values: [3 3 4 5 4 5 6 6 7 7 8]
set values: [3 3 4 5 4 5 6 6 7 7 8 9]
Worker 0 received 2
get values: [3 4 5 4 5 6 6 7 7 8 9]
set values: [3 4 5 4 5 6 6 7 7 8 9 8]
Worker 0 received 3
get values: [4 5 4 5 6 6 7 7 8 9 8]
set values: [4 5 4 5 6 6 7 7 8 9 8 10]
set values: [4 5 4 5 6 6 7 7 8 9 8 10 9]
Worker 0 received 3
get values: [5 4 5 6 6 7 7 8 9 8 10 9]
set values: [5 4 5 6 6 7 7 8 9 8 10 9 11]
set values: [5 4 5 6 6 7 7 8 9 8 10 9 11 10]
Worker 0 received 4
get values: [4 5 6 6 7 7 8 9 8 10 9 11 10]
set values: [4 5 6 6 7 7 8 9 8 10 9 11 10 11]
set values: [4 5 6 6 7 7 8 9 8 10 9 11 10 11 12]
bye

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

go routine channel select 的相关文章

  • 选择不带 FROM 但有多于一行的选择

    如何在不从现有表中进行选择的情况下生成 2 行 2 列的表 我正在寻找的是一个返回的选择语句 e g id value 1 103 2 556 Use UNION http dev mysql com doc refman 5 0 en u
  • 如何终止正在运行的 SELECT 语句

    如何通过终止会话来停止正在运行的 SELECT 语句 该命令不断根据 SELECT 语句向我提供输出 我想在其间停止它 As you keep getting pages of results I m assuming you starte
  • 每行中非空列的计数

    我有一个包含 4 列的表 在第 5 列中我想存储前 4 列中有多少个非空列的计数 例如 其中 X 是任意值 Column1 Column2 Column3 Column4 Count X X NULL X 3 NULL NULL X X 2
  • 使用 Socket.io 向多个房间发送消息?

    是否可以使用socket io向多个房间发送消息 发送至 1 个房间 io sockets in room emit id 发送到N个房间 io sockets in room1 room2 roomN emit id 是的 可以同时发送到
  • SQL Server - 将行连接到逗号分隔的列表中

    假设我有一个临时表 如下所示 Id Value 1 1 1 2 1 3 2 1 2 2 我希望我的桌子是这样的 Id ValueList 1 1 2 3 2 1 2 所以基本上我需要将我的值分组为逗号分隔的列表 我已经尝试过以下操作 SEL
  • MySQL - 选择一行 - 然后相对于所选行的下一个和上一个

    我会尽力澄清这一点 我需要在不使用 id 的情况下选择特定行和该选定行的前一个相对行以及该选定行的下一个相对行 这可能吗 简而言之 上一篇和下一篇 我不能 也许我只是不知道如何 使用 id 的原因是因为它们不是按顺序排列的 正如您从这个相当
  • postgresql 不同的不工作

    我使用以下代码从数据库获取值 但是当我编写这段代码时 测试看看问题出在哪里 我注意到查询没有从数据库中获取不同的值 这是查询 select distinct ca id as id acc name as accName pIsu name
  • 如何重新加载 jquery dropkick 对象

    我使用一个简单的选择列表和 jquery dropkick 库来使其美观 现在我想在更改相应的选择元素后更改 dropkick 内容 出现了一个新选项 但只需调用 select dropkick 不起作用 而且好像不支持 只需从头开始重建那
  • 作为 UDF 结果的列上的 Where 子句

    我有一个用户定义的函数 例如myUDF a b 返回一个整数 我试图确保该函数仅被调用一次 并且其结果可以用作WHERE clause SELECT col1 col2 col3 myUDF col1 col2 AS X From myTa
  • 在一个查询中对同一个表进行多个 COUNT SELECT

    对于某些人来说 这可能看起来很简单 但我就是无法理解 我一遍又一遍地从同一个表中进行多个 MS SQL SELECT 查询 SELECT count Page as tAEC FROM someTable WHERE Page LIKE A
  • MySQL select with 语句

    我正在学习更多 SQL 并遇到了一个 问题 我有两个表 如下面的链接http www sqlfiddle com 2 403d4 1 http www sqlfiddle com 2 403d4 1 编辑 由于我这个周末所做的所有 SQL
  • T-SQL 将集合分组到单个列中,没有 NULL 重复项

    一个同义词库数据库 其中术语和类别相互链接并运行 SQL Server 2008 基于this https stackoverflow com questions 4301074 t sql select combine multiple
  • SQL Server 转换选择一列并将其转换为字符串

    是否可以编写一条从表中选择列并将结果转换为字符串的语句 理想情况下 我希望有逗号分隔的值 例如 假设 SELECT 语句看起来像这样 SELECT column FROM table WHERE column lt 10 结果是一列包含值的
  • 使用 jQuery 按标题选择 div

    我有一个带有 div 的网页 其中包含其他几个没有关联 ID 的 div div div title jhon style width 8px height 9px div div title carl style width 8px he
  • MySQL 选择第一个字符在哪里

    如何选择单元格的第一个字符并使用它来定义返回的内容 看看MySQL 字符串 和 控制流 功能 http dev mysql com doc refman 5 1 en functions html 例如 SELECT IF LEFT myF
  • 子查询在多项选择时返回超过 1 个值的 SQL 错误

    我想要一个临时表 它将使用 select 语句插入值 但每次我运行查询时 总是出现错误 子查询返回超过 1 个值 当查询跟随 gt 或子查询用作表达式时 不允许这样做 该语句已终止 0 行受影响 这很奇怪 因为代码中似乎没有错误 但如果有的
  • Dplyr select_ 和starts_with 对变量列表中的多个值进行选择

    我正在从不同位置的不同传感器收集数据 数据输出类似于 df lt data frame date c 2011 2012 2013 2014 2015 Sensor1 Temp c 15 18 15 14 19 Sensor1 Pressu
  • 如何使用另一个表中存在的列名创建表?

    我正在研究 SQL Server 2016 我想知道是否可以创建一个永久或临时表 其列名存在于另一个表中 请参阅下表 MAINTAGS 及其代码 我希望 DOB 作为我的第一栏 POB 作为第二栏 依此类推 目前我的 MAINTAGS 表中
  • 使用 MS Access 获取行的第一个实例

    EDITED 我有这个查询 我想SELECT表中记录的第一个实例petTable SELECT id pet ID FIRST petName First Description FROM petTable GROUP BY pet ID
  • 使用 where 进行 select 语句时,HSQLDB 用户缺乏权限或未找到对象错误

    我的数据库使用 SQuirrel SQL 客户端版本 3 5 3 和 HSQLDB 我已经能够为其指定相应的驱动程序 内存中 并创建一个别名 我创建了一个表 CREATE TABLE ENTRY NAME VARCHAR 100 NOT N

随机推荐

  • python多线程爬虫教学,清晰易懂。

    首先需要知道什么是多线程 xff0c 多线程的作用 首先举个例子 xff0c 并发和并行 xff1a 并发 xff1a 并发 xff0c 在操作系统中 xff0c 是指一个时间段中有几个程序都处于已启动运行到运行完毕之间 xff0c 且这几
  • Matlab 读取txt文本中的数据

    使用matlab读取txt文本中的数据 数据最好有一定的规律 我们可以使用函数importdata来导入数据 下面使用一个例子来说明该函数的使用 start path C 设置默认文件夹 filename pathname uigetfil
  • 2018-07-25-github-如何在Github上面创建Release

    github release 看别的Github项目都有一条类似timeline 时间线 的版本列表 xff0c 如下图 xff0c 所以在Github上面摸索了一下 xff0c 弄好了记录一下 创建一个Release TestBefore
  • SSH登录卡在‘Last login‘提示界面的一种原因

    以前解决过SSH登录卡顿的问题 xff0c 它一般来源于 xff1a GSSAPIAuthentication UseDNS 以上设置项被默认打开或意外打开 而这次遇到的问题不是卡顿 xff0c 而是卡在 Last login xff0c
  • 【云原生之Docker实战】使用Docker部署openwrt软路由

    云原生之Docker实战 使用Docker部署openwrt软路由 一 openwrt介绍 二 检查本地docker状态 1 查看docker版本 2 查看docker信息 3 查看本地docker网络 三 安装docker compose
  • 值得收藏:图解算法——动态规划系列

    个人博客导航页 xff08 点击右侧链接即可打开个人博客 xff09 xff1a 大牛带你入门技术栈 小浩 xff1a 宜信科技中心攻城狮一枚 xff0c 热爱算法 xff0c 热爱学习 xff0c 不拘泥于枯燥编程代码 xff0c 更喜欢
  • TensorFlow之循环神经网络&自然语言处理 学习总结

    作者 xff1a jliang https blog csdn net jliang3 junliang 20190303 说明 xff1a 以下所有代码使用版本TensorFlow1 4 0或1 12 0版本 import tensorf
  • Docker镜像容器的迁移问题

    本文是本人项目踩坑经验 xff0c 如有错漏请见谅 xff01 背景需求 xff1a 一个已经配置好的容器 xff08 无build文件 xff09 需要部署到生产环境中 xff0c 容器内有程序绑定了宿主环境的硬件信息 需求部署后能让第三
  • 视觉里程计1 高翔

    小白 xff08 我 xff09 本着学习 xff0c 提高自我 xff0c 增加知识的想法 xff0c 决定认真分析高翔博士slam 在此立下一个flag xff1a 每周进行知识总结 xff08 CSDN xff09 xff1b 每周要
  • InvokeHelper函数的用法

    ActiveX控件的方法和属性操作与生成的C 43 43 类成员函数相关联都是通过InvokeHelper函数的调用来完成的 xff0c InvokeHelper函数的第一个参数是由Component Gallery xff08 控件提供者
  • 前向声明! struct netif; —— 只声明,无具体内部细节

    今天在看到 Linux阅码场 的 宋宝华 xff1a Linux内核编程广泛使用的前向声明 Forward Declaration xff0c 非常感谢 xff01 前向声明 编程定律 先强调一点 xff1a 在一切可能的场景 xff0c
  • MCU初始化流程——从上电到main()之间

    说明 xff1a 以下介绍示例的MCU地址空间如下 xff1a ROM空间为 xff1a 0x0000 0000 0x0000 8000 RAM空间为 xff1a 0x2000 0000 0x2000 2000 堆栈 SP 生长方向为 递减
  • FreeRTOS 启动第一个任务 prvStartFirstTask vPortSVCHandler

    asm void prvStartFirstTask void asm void prvStartFirstTask void PRESERVE8 Use the NVIC offset register to locate the sta
  • 组播知识 - IGMP

    https zhuanlan zhihu com p 258619129 组播初识 一 为什么要启用组播 xff1f 1 节省不必要的数据发送 2 需要发送相同的数据去往多个不同的接收者 3 减少带宽的占用 4 优化网络设备的处理进程 5
  • copy_from_user函数详细分析

    copy from user函数的目的是从用户空间拷贝数据到内核空间 xff0c 失败返回没有被拷贝的字节数 xff0c 成功返回0 这么简单的一个函数却含盖了许多关于内核方面的知识 比如内核关于异常出错的处理 从用户空间拷贝数据到内核中时
  • linux驱动中的宏 _IOC_NR, _IOC_TYPE, _IOC_SIZE, _IOC_DIR

    转载自 xff1a http blog csdn net u010245383 article details 29391805 虽然排版都点点乱 xff0c 但是内容还是较全面的 在驱动程序里 xff0c ioctl 函数上传送的变量 c
  • 【转载】更进一步的了解Keil Flash的下载算法

    转载自 xff1a https jingyan baidu com article 414eccf64f03be6b431f0af8 html 前面提到了通用算法的选择 xff0c 那么问题来了 xff0c 这个算法文件如何来的呢 xff1
  • 自己动手写操作系统-经典书籍

    汇编语言 xff0c 王爽编写 王爽老师这本书 xff0c 绝对是经典中的经典 xff0c 比其他介绍汇编语言的书强很多 这本书以例子贯穿整本书 不像其他书罗列一堆指令 这本书只介绍了常用指令 xff0c 而且每个指令都有例子 xff0c
  • golang 闭包 函数作为参数和返回值

    一 函数闭包 package main import 34 fmt 34 func adder func int int 函数作为返回值 sum 61 0 自由变量 xff0c 每次调用都保留上次的结果 return func v int
  • go routine channel select

    一 go routine channel package main import 34 fmt 34 34 time 34 func worker id int c chan int for n 61 range c 读取channel f