关于go语言的通道
1、记一次gorountine导致的泄漏
在项目中使用https://github.com/deckarep/golang-set这个三方包造成了gorountine泄漏。先来看一下这个包的迭代器设置,如下:
package mapset // Iterator defines an iterator over a Set, its C channel can be used to range over the Set's // elements. type Iterator struct { C <-chan interface{} stop chan struct{} } // Stop stops the Iterator, no further elements will be received on C, C will be closed. func (i *Iterator) Stop() { // Allows for Stop() to be called multiple times // (close() panics when called on already closed channel) defer func() { recover() }() close(i.stop) // Exhaust any remaining elements. for range i.C { } } // newIterator returns a new Iterator instance together with its item and stop channels. func newIterator() (*Iterator, chan<- interface{}, <-chan struct{}) { itemChan := make(chan interface{}) stopChan := make(chan struct{}) return &Iterator{ C: itemChan, stop: stopChan, }, itemChan, stopChan }
这样,向外提供API时的代码如下:
func (set *threadSafeSet) Iterator() *Iterator { iterator, ch, stopCh := newIterator() go func() { set.RLock() L: for elem := range set.s { select { case <-stopCh: break L case ch <- elem: } } close(ch) set.RUnlock() }() return iterator }
正确的使用方法如下:
type YourType struct { Name string } func ExampleIterator() { set := NewSetFromSlice([]interface{}{ &YourType{Name: "Alise"}, &YourType{Name: "Bob"}, &YourType{Name: "John"}, &YourType{Name: "Nick"}, }) var found *YourType it := set.Iterator() for elem := range it.C { if elem.(*YourType).Name == "John" { found = elem.(*YourType) it.Stop() } } fmt.Printf("Found %+v\n", found) // Output: Found &{Name:John} }
还有另外一个方法,如下:
func (set *threadSafeSet) Iter() <-chan interface{} { ch := make(chan interface{}) go func() { set.RLock() for elem := range set.s { ch <- elem } close(ch) set.RUnlock() }() return ch }
这个方法必须遍历完所有的elem元素,否则会造成gorountine阻塞。所以切不可在循环之内break。
2、理解chan chan类型
一个小Demo有助于理解,代码如下:
import ( "time" "fmt" ) func main() { // make the request chan chan that both go-routines will be given requestChan := make(chan chan string) // start the goroutines go goroutineC(requestChan) go goroutineD(requestChan) // sleep for a second to let the goroutines complete time.Sleep(time.Second) } func goroutineC(requestChan chan chan string) { // make a new response chan responseChan := make(chan string) // send the responseChan to goRoutineD requestChan <- responseChan // read the response response := <-responseChan fmt.Printf("Response: %v\n", response) } func goroutineD(requestChan chan chan string) { // read the responseChan from the requestChan responseChan := <-requestChan // send a value down the responseChan responseChan <- "wassup!" }
chan chan类型有非常大的用处,如实现每分钟百万流量的处理。
参考:
(1)http://tleyden.github.io/blog/2013/11/23/understanding-chan-chans-in-go/
(2)https://www.goin5minutes.com/blog/channel_over_channel/
(3)http://marcio.io/2015/07/handling-1-million-requests-per-minute-with-golang/
关于go语言的通道的更多相关文章
- Go语言的通道(1)-无缓冲通道
前言: 上文中我们采用了[原子函数]已经[共享锁]两种方式分别对多个goroutine进行了同步,但是在go语言中提供了另一种更好的方式,那就是使用通道(Channel). 一.通道是什么? 其实无论 ...
- Go语言的通道(2)-缓冲通道
有缓冲的通道相比于无缓冲通道,多了一个缓存的功能,如下图描述的一样: 从图上可以明显看到和无缓冲通道的区别,无缓冲必须两个Goroutine都进入通道才能进行数据的交换,这个不用,如果数据有,直接就能 ...
- Go语言规格说明书 之 通道 发送语句(send) 和 接收操作符(receive)
go version go1.11 windows/amd64 本文为阅读Go语言中文官网的规则说明书(https://golang.google.cn/ref/spec)而做的笔记,介绍Go语言的 ...
- Go语言规格说明书 之 通道类型(Channel types)
go version go1.11 windows/amd64 本文为阅读Go语言中文官网的规则说明书(https://golang.google.cn/ref/spec)而做的笔记,介绍Go语言的 ...
- 027_go语言中的通道选择器
代码演示 package main import "fmt" import "time" func main() { c1 := make(chan strin ...
- Go语言程序设计(1)--基本语法
第一个程序 package main import "fmt" func main() { fmt.Printf("Hello world") } 通过阅读这个 ...
- 掌握一门语言Go
摘要:Go语言的优势不必多说,通过本篇文章,让我们花时间来掌握一门外语,Let's Go! 关键字:Go语言,闭包,基本语法,函数与方法,指针,slice,defer,channel,goroutin ...
- Go语言之并发编程(二)
通道(channel) 单纯地将函数并发执行是没有意义的.函数与函数间需要交换数据才能体现并发执行函数的意义.虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题 ...
- 高手问答精选:Go 语言 —— 云计算时代的 C 语言(类似于一个FAQ)
Go 语言被称为云计算时代的 C 语言,它在软件开发效率和运行效率之间做出了绝佳的权衡.这使得它既适应于互联网应用的极速开发,又能在高并发.高性能的开发场景中如鱼得水.正因如此,许多互联网公司,尤其是 ...
随机推荐
- Python模块 - paramiko
paramiko模块提供了ssh及sft进行远程登录服务器执行命令和上传下载文件的功能.这是一个第三方的软件包,使用之前需要安装. 1 基于用户名和密码的 sshclient 方式登录 # 建立一个s ...
- hdu-2602&&POJ-3624---01背包裸题
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2602 https://vjudge.net/problem/POJ-3624 都是01背包的裸题 这 ...
- hdu1022 Train Problem I---模拟栈
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1022 题目大意: 车的进出站问题,先给出N个火车,再按序列一的方式进站,判断能否以序列二的方式出站,若 ...
- python判断素数的方法
#运用python的数学函数 import math def isPrime(n): if n <= 1: return False for i in range(2, int(math.sqr ...
- (CLR-Via-C#) 类型基础
CLR要求每个类型最终都派生自System.Object Object提供的公共方法: Equals: 如果两个对象具有相同的值,就返回true GetHashCode: 返回对象的哈希码 ToStr ...
- 使用 Docker 一步搞定 ZooKeeper 集群的搭建
背景 原来学习 ZK 时, 我是在本地搭建的伪集群, 虽然说使用起来没有什么问题, 但是总感觉部署起来有点麻烦. 刚好我发现了 ZK 已经有了 Docker 的镜像了, 于是就尝试了一下, 发现真是爽 ...
- java中抽象类和接口之间的异同点
抽象类 接口 声明方式 abstratc class ClassName interface ClassName 包含内容 构造方法,普通方法,抽象方法.static方法 .变量常量 全局常量.抽 ...
- linux下使用crontab定时执行脚本
使用crontab定时执行脚本 cron服务是一个定时执行的服务,可以通过crontab 命令添加或者编辑需要定时执行的任务: crontab –e : 修改 crontab 文件,如果文件不存在会自 ...
- 一个web程序员的年终总结
2017年年终总结(就是一个程序员的瞎叨叨): 从来到中科院到现在,很开心可以在这留下来.毕竟对于我来说,这里符合我对自己毕业后前两年的规划.我是一个很慢的人,特别是对于我想做好的事情,我会非常认真仔 ...
- 【linux之sed及vim】
一.sed sed 文本处理工具 流编辑器 行编辑器保留空间模式空间sed不会影响原文件的内容,它处理的是它载入模式空间的内容 sed [options].."AddressCommand& ...