关于go语言的通道

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

 

 

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/

 

 

 

 

 

 

 

 

 

 

 

 


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

本文来自:博客园

感谢作者:mazhimazhi

查看原文:关于go语言的通道

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

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