热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

go并发编程36——管道(channel)

channel的类型*channel实现同步*packagemainimport(fmttime)创建一个管道varchmake(chanint)funcPri
channel的类型

/*
channel实现同步
*/
package mainimport ("fmt""time"
)//创建一个管道
var ch = make(chan int)func Print(s string) {for _, data := range s {fmt.Printf("%c", data)time.Sleep(time.Second)}fmt.Println("\n")
}//目标:先打印hello 再打印go
func Person1() {Print("hello")ch <- 1 //给管道写数据(发送) "1"只是用于举例
}func Person2() {<-ch //从管道取数据(接收)&#xff0c;如果通道没有数据&#xff0c;会阻塞Print("go")
}func main() {//新建两个协程go Person1()go Person2()for {}
}

通过channel实现同步和数据交互

package mainimport ("fmt""time"
)func main() {//创建管道ch :&#61; make(chan string)defer fmt.Println("主协程结束")go func() {defer fmt.Println("子协程调用完毕")for i :&#61; 0; i <2; i&#43;&#43; {fmt.Println("i &#61; ", i)time.Sleep(time.Second)}ch <- "q"}()str :&#61; <-ch //没有数据前&#xff0c;会阻塞fmt.Println("str &#61; ", str)
}

无缓冲的channel

package mainimport ("fmt""time"
)func main() {//创建无缓冲的通道ch :&#61; make(chan int, 0)//len(ch)缓冲区剩余数据个数&#xff0c;cap(ch)缓冲区大小fmt.Printf("len(ch) &#61; %d, cap(ch) &#61; %d\n", len(ch), cap(ch))go func() {for i :&#61; 0; i <3; i&#43;&#43; {fmt.Println("子协程:i &#61; ", i)ch <- i //ch中的数据没有被读出去之前会阻塞在这}}()time.Sleep(2 * time.Second)for i :&#61; 0; i <3; i&#43;&#43; {num :&#61; <-chfmt.Println("num &#61; ", num)}
}

有缓冲的channel

/*
格式: make(chan type, capacity)
如果给定缓冲区容量&#xff0c;通道是异步的。只要缓冲区有未使用的空间用于发送数据&#xff0c;或者还包括
可以接收的数据&#xff0c;那么其通信就会无阻塞的进行
*/
package mainimport ("fmt""time"
)func main() {//创建有缓冲的通道ch :&#61; make(chan int, 3)fmt.Printf("len(ch) &#61; %d, cap(ch) &#61; %d\n", len(ch), cap(ch)) //len(ch):0 cap(ch):3go func() {for i :&#61; 0; i <10; i&#43;&#43; {ch <- i //ch满之后不能再写fmt.Printf("子协程[%d]:len(ch) &#61; %d, cap(ch) &#61; %d\n", i, len(ch), cap(ch))}}()time.Sleep(2 * time.Second)for i :&#61; 0; i <10; i&#43;&#43; {num :&#61; <-chfmt.Println("num &#61; ", num)}
}

关闭channel

/*
1. 关闭channel后&#xff0c;无法向channel再发送数据(引发panic错误后导致接收立即返回0)
2. 关闭channel后&#xff0c;可以继续向channel接收数据
3. 对于nil channel,无论收发都会别阻塞
*/
package mainimport ("fmt"
)func main() {//创建无缓冲的通道ch :&#61; make(chan int, 0)go func() {for i :&#61; 0; i <5; i&#43;&#43; {ch <- i //写数据}//不需要再写数据时&#xff0c;关闭channelclose(ch) //屏蔽此行会死锁 无法跳出下面的死循环//ch <- 1 //关闭channel后无法再发送数据}()//方法1/*for {//如果ok为true,说明ch没有关闭num, ok :&#61; <-ch //读数据if ok &#61;&#61; true {fmt.Println("num &#61; ", num)} else {break}}*///方法2for num :&#61; range ch {fmt.Println("num &#61; ", num)}
}

单向channel的特性

package main//import "fmt"func main() {//创建一个channelch :&#61; make(chan int)//双向channel可以隐式转换为单向channelvar wCh chan<- int &#61; ch //只写wCh <- 12//<-wChch <- 12var rCh <-chan int &#61; ch //只读<-rCh//rCh <- 11//单向是无法转换为双向的//var ch2 chan int &#61; rCh
}

单向channel的应用

package mainimport "fmt"//此通道只能写不能读
func Producer(wCh chan<- int) {for i :&#61; 0; i <10; i&#43;&#43; {wCh <- i * i}close(wCh)
}//只能读 不能写
func Consumer(rCh <-chan int) {for num :&#61; range rCh { //rCh没有数据会阻塞fmt.Println("num &#61; ", num)}
}func main() {//创建一个双向通道ch :&#61; make(chan int)//生产者go Producer(ch) //channel传参是引用传递//消费者Consumer(ch)
}

timer

package mainimport ("fmt""time"
)func main() {//创建一个定时器&#xff0c;设置时间为2s&#xff0c;2s后&#xff0c;往time通道写数据(当前时间)//时间到了 timer只会响应一次timer :&#61; time.NewTimer(2 * time.Second)fmt.Println("当前时间:", time.Now())//2s后&#xff0c;往timer.C写数据&#xff0c;有数据后&#xff0c;就可以读取t :&#61; <-timer.C //channel没有数据前会阻塞fmt.Println("t &#61; ", t)
}

通过timer实现延时

/*
延时的3种方式
sleep.go
*/
package mainimport ("fmt""time"
)func main() {//方式1time.Sleep(2 * time.Second)//方式2 定时2s 阻塞2s 2s后会产生一个事件 往channel写数据<-time.After(2 * time.Second)//方式3//延时2s后打印一句话timer :&#61; time.NewTimer(2 * time.Second)<-timer.C //时间未到会阻塞fmt.Println("时间到")}

定时器停止和重置

package mainimport ("fmt""time"
)func main() {timer :&#61; time.NewTimer(3 * time.Second)b :&#61; timer.Reset(1 * time.Second) //定时器重置fmt.Println("b &#61; ", b)<-timer.Cfmt.Println("时间到") //3s后打印
}func main1() {timer :&#61; time.NewTimer(3 * time.Second)go func() { //创建一个匿名函数作为子协程<-timer.C //3s过后停止阻塞 执行下面的打印fmt.Println("定时器时间到,子协程打印")}()timer.Stop() //停止定时器for { //主协程死循环}
}

Ticker

package mainimport ("fmt""time"
)func main() {ticker :&#61; time.NewTicker(1 * time.Second)i :&#61; 0for {<-ticker.Ci&#43;&#43;fmt.Println("i &#61; ", i)if i &#61;&#61; 5 {ticker.Stop()break}}
}


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了在多平台下进行条件编译的必要性,以及具体的实现方法。通过示例代码展示了如何使用条件编译来实现不同平台的功能。最后总结了只要接口相同,不同平台下的编译运行结果也会相同。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 本文介绍了基于c语言的mcs51单片机定时器计数器的应用教程,包括定时器的设置和计数方法,以及中断函数的使用。同时介绍了定时器应用的举例,包括定时器中断函数的编写和频率值的计算方法。主函数中设置了T0模式和T1计数的初值,并开启了T0和T1的中断,最后启动了CPU中断。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文讨论了如何使用IF函数从基于有限输入列表的有限输出列表中获取输出,并提出了是否有更快/更有效的执行代码的方法。作者希望了解是否有办法缩短代码,并从自我开发的角度来看是否有更好的方法。提供的代码可以按原样工作,但作者想知道是否有更好的方法来执行这样的任务。 ... [详细]
  • 多维数组的使用
    本文介绍了多维数组的概念和使用方法,以及二维数组的特点和操作方式。同时还介绍了如何获取数组的长度。 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
author-avatar
小小的梦想123
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有