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语言的通道的更多相关文章

  1. Go语言的通道(1)-无缓冲通道

    前言: 上文中我们采用了[原子函数]已经[共享锁]两种方式分别对多个goroutine进行了同步,但是在go语言中提供了另一种更好的方式,那就是使用通道(Channel). 一.通道是什么? 其实无论 ...

  2. Go语言的通道(2)-缓冲通道

    有缓冲的通道相比于无缓冲通道,多了一个缓存的功能,如下图描述的一样: 从图上可以明显看到和无缓冲通道的区别,无缓冲必须两个Goroutine都进入通道才能进行数据的交换,这个不用,如果数据有,直接就能 ...

  3. Go语言规格说明书 之 通道 发送语句(send) 和 接收操作符(receive)

    go version go1.11 windows/amd64 本文为阅读Go语言中文官网的规则说明书(https://golang.google.cn/ref/spec)而做的笔记,介绍Go语言的 ...

  4. Go语言规格说明书 之 通道类型(Channel types)

    go version go1.11 windows/amd64 本文为阅读Go语言中文官网的规则说明书(https://golang.google.cn/ref/spec)而做的笔记,介绍Go语言的 ...

  5. 027_go语言中的通道选择器

    代码演示 package main import "fmt" import "time" func main() { c1 := make(chan strin ...

  6. Go语言程序设计(1)--基本语法

    第一个程序 package main import "fmt" func main() { fmt.Printf("Hello world") } 通过阅读这个 ...

  7. 掌握一门语言Go

    摘要:Go语言的优势不必多说,通过本篇文章,让我们花时间来掌握一门外语,Let's Go! 关键字:Go语言,闭包,基本语法,函数与方法,指针,slice,defer,channel,goroutin ...

  8. Go语言之并发编程(二)

    通道(channel) 单纯地将函数并发执行是没有意义的.函数与函数间需要交换数据才能体现并发执行函数的意义.虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题 ...

  9. 高手问答精选:Go 语言 —— 云计算时代的 C 语言(类似于一个FAQ)

    Go 语言被称为云计算时代的 C 语言,它在软件开发效率和运行效率之间做出了绝佳的权衡.这使得它既适应于互联网应用的极速开发,又能在高并发.高性能的开发场景中如鱼得水.正因如此,许多互联网公司,尤其是 ...

随机推荐

  1. leetcode算法:Island Perimeter

    You are given a map in form of a two-dimensional integer grid where 1 represents land and 0 represen ...

  2. String、StringBuffer、StringBulider之间的联系和区别

    首先,我们大概总体的解释一下这三者的区别和联系 String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间. StringBuf ...

  3. python Django注册页面显示头像

    python Django注册页面显示头像(views) def register(request): ''' 注册 :param request: :return: ''' if request.m ...

  4. Python_fullstack_test1

    1.执行Python脚本的两种方式 使用交互式的带提示符的解释器或使用源文件 2.简述位.字节的关系 位是计算机中最小计量单位,用bit表示 字节是计算机中最小存储单位,用Byte表示 1字节=8位, ...

  5. PageRank之基于C C#的基本实现

    重点不是说PageRank是什么,而是怎么用代码实现 什么是PageRank? PageRank,网页排名,又称网页级别.Google左侧排名或佩奇排名,是一种由[1]  根据网页之间相互的超链接计算 ...

  6. SpringBoot开发案例之多任务并行+线程池处理

    前言 前几篇文章着重介绍了后端服务数据库和多线程并行处理优化,并示例了改造前后的伪代码逻辑.当然了,优化是无止境的,前人栽树后人乘凉.作为我们开发者来说,既然站在了巨人的肩膀上,就要写出更加优化的程序 ...

  7. 在Unity3D中利用 RenderTexture 实现游戏内截图

    using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; publ ...

  8. NC的开发模型

    2018-04-1622:35:12 NC的开发模型 系统前端为:客户UI代码,UI代码继承ToftPanel,UI代码通过调用远程组件和服务端进行交互,中间传递的数据模型为VO,远程组件调用底层的业 ...

  9. 持久化 XSS:ServiceWorkers 利用

    来源:http://www.mottoin.com/95058.html 来源:https://www.owasp.org/images/3/35/2017-04-20-JSONPXSS.pdf Se ...

  10. EventBus InMemory 的实践基于eShopOnContainers (二)

    前言 最近在工作中遇到了一个需求,会用到EventBus,正好看到eShopOnContainers上有相关的实例,去研究了研究.下面来分享一下用EventBus 来改造一下我们上篇Event发布与实 ...