分享
  1. 首页
  2. 文章

golang 并发 chan

hezuideda · · 24198 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

channels 是 goroutines之间通信的工具, 可以理解为管道, 虽然go也提供共享变量的方式, 但是更加推荐使用channel

func TestChan(t *testing.T) {
	c := make(chan int)
	go func() {
		c <- 48
	}()
	fmt.Println(<- c)
	// 保持持续运行
	holdRun()
}
func holdRun() {
	time.Sleep(1 * time.Hour)
}

c := make(chan int) 声明一个 传输整形 的unbuffer chan,(接收消息和发送消息者将会阻塞,直到channel "可用")

<- 操作符用来接受和发送消息 chan <- 48 发送"48" 进入管道, <-chan 接收消息

如果: c: = make(chan int, 10) 声明一个 传输整形 的buffer chan, 容量为10, 接收消息将可以立即返回除非channel里面没有消息, 发送者返回除非容量满


func TestDeadLock(t *testing.T) {
	c := make(chan int)
	c <- 42
	val := <-c
	fmt.Println(val)
}
func TestDeadLock1(t *testing.T) {
	c := make(chan int)
	//c := make(chan int, 0)
	go func() {
		c <- 48
	}()
	val := <-c
	fmt.Println(val)
}
func TestDeadLock2(t *testing.T) {
	c := make(chan int, 1)
	c <- 42
	val := <-c
	fmt.Println(val)
}
对于方法, TestDeadLock 将:fatal error: all goroutines are asleep - deadlock! 因为c <- 42 将会一直阻塞,直到出现消费者, 无容量的chan是同步, 正确的写法是 TestDeadLock1 这样不会死锁, 或者 TestDeadLock2 也不会死锁
func TestChan(t *testing.T) {
	c := make(chan int, 10)
	go func() {
		c <- 48
		c <- 96
		time.Sleep(2 * time.Second)
		c <- 200
	}()
	time.Sleep(1 * time.Second)
	for v := range c {
		fmt.Println(v)
	}
	// 保持持续运行
	holdRun()
}
chan 可以配合 range 使用, 相当于每次foreach 每次去取一次


func TestDChan(t *testing.T) {
	c := make(chan int)
	go f1(c)
	holdRun()
}
func f1(c chan <- int) {
	c <- 0
	<- c 
}
f1的参数类型是 chan <- int 表明 这个chan单向的, 只能用来接收。 f1函数编译错误:invalid operation: <-c (receive from send-only type chan<- int)

相对应的发送的chan : c <-chan string


select 关键字可以和 chan使用, 类似与switch

func TestSelect(t *testing.T) {
	c1 := make(chan int)
	c2 := make(chan int, 10)
	c3 := make(chan int, 20)
	go func(c1, c2, c3 chan<- int) {
		for {
			time.Sleep(1 * time.Second)
			c1 <- 1
			time.Sleep(1 * time.Second)
			c1 <- 1
			time.Sleep(1 * time.Second)
			c1 <- 2
			time.Sleep(1 * time.Second)
			c1 <- 3
		}
	}(c1, c2, c3)
	for {
		select {
		case int1 := <-c1:
			fmt.Println("c1 value :", int1)
		case int2 := <-c2:
			fmt.Println("c2 value :", int2)
		case int3 := <-c3:
			fmt.Println("c3 vaule :", int3)
		case <-time.After(2 * time.Second):
			fmt.Println("timeount")
		}
	}
}
select 将阻塞直到有一个chan ready或者 超时,即 time.After


select {
		case int1 := <-c1:
			fmt.Println("c1 value :", int1)
		case int2 := <-c2:
			fmt.Println("c2 value :", int2)
		case int3 := <-c3:
			fmt.Println("c3 vaule :", int3)
		default:
			fmt.Println("nothing ready")
		}

select 将不会阻塞, 直接执行 default


附 :

time.Afer 实现:

func After(d Duration) <-chan Time {
	return NewTimer(d).C
}


func NewTimer(d Duration) *Timer {
	c := make(chan Time, 1)
	t := &Timer{
		C: c,
		r: runtimeTimer{
			when: when(d),
			f: sendTime,
			arg: c,
		},
	}
	startTimer(&t.r)
	return t
}

NewTimer 返回一个 timer (timer是一个一次性时间,d 时间后 发送当前时间给 C) , 由于C在此之前会一直阻塞。从而达到超时的效果





有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:hezuideda

查看原文:golang 并发 chan

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
24198 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏