婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁(yè) > 知識(shí)庫(kù) > 再次探討go實(shí)現(xiàn)無(wú)限 buffer 的 channel方法

再次探討go實(shí)現(xiàn)無(wú)限 buffer 的 channel方法

熱門(mén)標(biāo)簽:如何利用高德地圖標(biāo)注家 電腦外呼系統(tǒng)輻射大嗎 百度地圖標(biāo)注位置網(wǎng)站 開(kāi)通400電話(huà)申請(qǐng)流程 智能語(yǔ)音電銷(xiāo)的機(jī)器人 武漢百應(yīng)人工智能電銷(xiāo)機(jī)器人 400手機(jī)電話(huà)免費(fèi)辦理 揚(yáng)州電銷(xiāo)外呼系統(tǒng)軟件 上海企業(yè)外呼系統(tǒng)排名

前言

總所周知,go 里面只有兩種 channel,一種是 unbuffered channel, 其聲明方式為

ch := make(chan interface{})

另一種是 buffered channel,其聲明方式為

bufferSize := 5
ch := make(chan interface{},bufferSize)

對(duì)于一個(gè) buffered channel,無(wú)論它的 buffer 有多大,它終究是有極限的。這個(gè)極限就是該 channel 最初被 make 時(shí),所指定的 bufferSize 。

jojo,buffer channel 的大小是有極限的,我不做 channel 了。

一旦 channel 滿(mǎn)了的話(huà),再往里面添加元素的話(huà),將會(huì)阻塞。

so how can we make a infinite buffer channel?

本文參考了 medinum 上面的一篇文章,有興趣的同學(xué)可以直接閱讀原文。

實(shí)現(xiàn)

接口的設(shè)計(jì)

首先當(dāng)然是建一個(gè) struct,在百度翻譯的幫助下,我們將這個(gè) struct 取名為 InfiniteChannel

type InfiniteChannel struct {
}

思考一下 channel 的核心行為,實(shí)際上就兩個(gè),一個(gè)流入(Fan in),一個(gè)流出(Fan out),因此我們添加如下幾個(gè) method。

func (c *InfiniteChannel) In(val interface{}) {
	// todo
}

func (c *InfiniteChannel) Out() interface{} {
	// todo
}

內(nèi)部實(shí)現(xiàn)

通過(guò) In() 接收的數(shù)據(jù),總得需要一個(gè)地方來(lái)存放。我們可以用一個(gè) slice 來(lái)存放,就算用 In() 往里面添加了很多元素,也可以通過(guò) append() 來(lái)拓展 sliceslice 的容量可以無(wú)限拓展下去(內(nèi)存足夠的話(huà)),所以 channel 也是 infiniteInfiniteChannel 的第一個(gè)成員就這么敲定下來(lái)的。

type InfiniteChannel struct {
	data    []interface{}
}

用戶(hù)調(diào)用 In()Out() 時(shí),可能是并發(fā)的環(huán)境,在 go 中如何進(jìn)行并發(fā)編程,最容易想到的肯定是 channel 了,因此我們?cè)趦?nèi)部準(zhǔn)備兩個(gè) channel,一個(gè) inChan,一個(gè) outChan,用 inChan 來(lái)接收數(shù)據(jù),用 outChan 來(lái)流出數(shù)據(jù)。

type InfiniteChannel struct {
	inChan  chan interface{}
	outChan chan interface{}
	data    []interface{}
}

func (c *InfiniteChannel) In(val interface{}) {
	c.inChan - val
}

func (c *InfiniteChannel) Out() interface{} {
	return -c.outChan
}

其中, inChanoutChan 都是 unbuffered channel。

此外,也肯定是需要一個(gè) select 來(lái)處理來(lái)自 inChanoutChan 身上的事件。因此我們另起一個(gè)協(xié)程,在里面做 select 操作。

func (c *InfiniteChannel) background() {
	for true {
		select {
		case newVal := -c.inChan:
			c.data = append(c.data, newVal)
        case c.outChan - c.pop():		// pop() 將取出隊(duì)列的首個(gè)元素
		}
	}
}
func NewInfiniteChannel() *InfiniteChannel {
	c := InfiniteChannel{
		inChan:  make(chan interface{}),
		outChan: make(chan interface{}),
	}
	go c.background()	// 注意這里另起了一個(gè)協(xié)程
	return c
}

ps:感覺(jué)這也算是 go 并發(fā)編程的一個(gè)套路了。即

  1. 在 new struct 的時(shí)候,順手 go 一個(gè) select 協(xié)程,select 協(xié)程內(nèi)執(zhí)行一個(gè) for 循環(huán),不停的 select,監(jiān)聽(tīng)一個(gè)或者多個(gè) channel 的事件。
  2. struct 對(duì)外提供的 method,只會(huì)操作 struct 內(nèi)的 channel(在本例中就是 inChan 和 outChan),不會(huì)操作 struct 內(nèi)的其他數(shù)據(jù)(在本例中,In() 和 Out() 都沒(méi)有直接操作 data)。
  3. 觸發(fā) channel 的事件后,由 select 協(xié)程進(jìn)行數(shù)據(jù)的更新(在本例中就是 data )。因?yàn)橹挥?select 協(xié)程對(duì)除 channel 外的數(shù)據(jù)成員進(jìn)行讀寫(xiě)操作,且 go 保證了對(duì)于 channel 的并發(fā)讀寫(xiě)是安全的,所以代碼是并發(fā)安全的。
  4. 如果 struct 是 exported ,用戶(hù)或許會(huì)越過(guò) new ,直接手動(dòng) make 一個(gè) struct,可以考慮將 struct 設(shè)置為 unexported,把它的首字母小寫(xiě)即可。

pop() 的實(shí)現(xiàn)也非常簡(jiǎn)單。

// 取出隊(duì)列的首個(gè)元素,如果隊(duì)列為空,將會(huì)返回一個(gè) nil
func (c *InfiniteChannel) pop() interface{} {
	if len(c.data) == 0 {
		return nil
	}
	val := c.data[0]
	c.data = c.data[1:]
	return val
}

測(cè)試一下

用一個(gè)協(xié)程每秒鐘生產(chǎn)一條數(shù)據(jù),另一個(gè)協(xié)程每半秒消費(fèi)一條數(shù)據(jù),并打印。

func main() {
	c := NewInfiniteChannel()
	go func() {
		for i := 0; i  20; i++ {
			c.In(i)
			time.Sleep(time.Second)
		}
	}()

	for i := 0; i  50; i++ {
		val := c.Out()
		fmt.Print(val)
		time.Sleep(time.Millisecond * 500)
	}
}
// out
nil>0nil>1nil>23nil>4nil>nil>5nil>67nil>nil>89nil>nil>1011nil>12nil>13nil>14nil>15nil>16nil>17nil>nil>1819nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>
Process finished with the exit code 0

可以看到,將 InfiniteChannel 內(nèi)沒(méi)有數(shù)據(jù)可供消費(fèi)時(shí),調(diào)用 Out() 將會(huì)返回一個(gè) nil,不過(guò)這也在我們的意料之中,原因是 pop() 在隊(duì)列為空時(shí),將會(huì)返回 nil。

目前 InfiniteChannel 的行為與標(biāo)準(zhǔn)的 channel 的行為是有出入的,go 中的 channel,在沒(méi)有數(shù)據(jù)卻仍要取數(shù)據(jù)時(shí)會(huì)被阻塞,如何實(shí)現(xiàn)這個(gè)效果?

優(yōu)化

我認(rèn)為此處是是整篇文章最有技巧的地方,我第一次看到時(shí)忍不住拍案叫絕。

首先把原來(lái)的 background() 摘出來(lái)

func (c *InfiniteChannel) background() {
	for true {
		select {
		case newVal := -c.inChan:
			c.data = append(c.data, newVal)
		case c.outChan - c.pop():
		}
	}
}

對(duì) outChan 進(jìn)行一個(gè)簡(jiǎn)單封裝

func (c *InfiniteChannel) background() {
	for true {
		select {
		case newVal := -c.inChan:
			c.data = append(c.data, newVal)
		case c.outChanWrapper() - c.pop():
		}
	}
}
func (c *InfiniteChannel) outChanWrapper() chan interface{} {
	return c.outChan
}

目前為止,一切照舊。

點(diǎn)睛之筆來(lái)了:

func (c *InfiniteChannel) outChanWrapper() chan interface{} {
	if len(c.data) == 0 {
		return nil
	}
	return c.outChan
}

c.data 為空的時(shí)候,返回一個(gè) nil

background() 中,當(dāng)執(zhí)行到 case c.outChan - c.pop(): 時(shí),實(shí)際上將會(huì)變成:

case nil - nil:

go 中,是無(wú)法往一個(gè) nilchannel 中發(fā)送元素的。例如

func main() {
	var c chan interface{}
	select {
	case c - 1:
	}
}
// fatal error: all goroutines are asleep - deadlock!
func main() {
	var c chan interface{}
	select {
	case c - 1:
	default:
		fmt.Println("hello world")
	}
}
// hello world

因此,對(duì)于

select {
case newVal := -c.inChan:
	c.data = append(c.data, newVal)
case c.outChanWrapper() - c.pop():
}

將會(huì)一直阻塞在 select 那里,直到 inChan 來(lái)了數(shù)據(jù)。

再測(cè)試一下

012345678910111213141516171819fatal error: all goroutines are asleep - deadlock!

最后,程序 panic 了,因?yàn)樗梨i了。

補(bǔ)充

實(shí)際上 channel 除了 In()Out() 外,還有一個(gè)行為,即 close(),如果 channel close 后,依舊從其中取元素的話(huà),將會(huì)取出該類(lèi)型的默認(rèn)值。

func main() {
	c := make(chan interface{})
	close(c)
	for true {
		v := -c
		fmt.Println(v)
		time.Sleep(time.Second)
	}
}
// output
// nil>
// nil>
// nil>
// nil>
func main() {
	c := make(chan interface{})
	close(c)
	for true {
		v, isOpen := -c
		fmt.Println(v, isOpen)
		time.Sleep(time.Second)
	}
}
// output
// nil> false
// nil> false
// nil> false
// nil> false

我們也需要實(shí)現(xiàn)相同的效果。

func (c *InfiniteChannel) Close() {
	close(c.inChan)
}

func (c *InfiniteChannel) background() {
	for true {
		select {
		case newVal, isOpen := -c.inChan:
			if isOpen {
				c.data = append(c.data, newVal)
			} else {
				c.isOpen = false
			}
		case c.outChanWrapper() - c.pop():
		}
	}
}

func NewInfiniteChannel() *InfiniteChannel {
	c := InfiniteChannel{
		inChan:  make(chan interface{}),
		outChan: make(chan interface{}),
		isOpen:  true,
	}
	go c.background()
	return c
}

func (c *InfiniteChannel) outChanWrapper() chan interface{} {
    // 這里添加了對(duì) c.isOpen 的判斷
	if c.isOpen  len(c.data) == 0 {
		return nil
	}
	return c.outChan
}

再測(cè)試一下

func main() {
	c := NewInfiniteChannel()
	go func() {
		for i := 0; i  20; i++ {
			c.In(i)
			time.Sleep(time.Second)
		}
		c.Close()		// 這里調(diào)用了 Close
	}()

	for i := 0; i  50; i++ {
		val := c.Out()
		fmt.Print(val)
		time.Sleep(time.Millisecond * 500)
	}
}
// output
012345678910111213141516171819nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>nil>
Process finished with the exit code 0

符合預(yù)期

遺憾

目前看上去已經(jīng)很完美了,但是和標(biāo)準(zhǔn)的 channel 相比,仍然有差距。因?yàn)闃?biāo)準(zhǔn)的 channel 是有這種用法的

v,isOpen := - ch

可以通過(guò) isOpen 變量來(lái)獲取 channel 的開(kāi)閉情況。

因此 InfiniteChannel 也應(yīng)該提供一個(gè)類(lèi)似的 method

func (c *InfiniteChannel) OutAndIsOpen() (interface{}, bool) {
	// todo
}

可惜的是,要想得知 InfiniteChannel 是否是 Open 的,就必定要訪(fǎng)問(wèn) InfiniteChannel 內(nèi)的 isOpen 成員。

type InfiniteChannel struct {
	inChan  chan interface{}
	outChan chan interface{}
	data    []interface{}
	isOpen  bool
}

isOpen 并非 channel 類(lèi)型,根據(jù)之前的套路,這種非 channel 類(lèi)型的成員只應(yīng)該被 select 協(xié)程訪(fǎng)問(wèn)。一旦有多個(gè)協(xié)程訪(fǎng)問(wèn),就會(huì)出現(xiàn)并發(fā)問(wèn)題,除非加鎖。

我不能接受!所以干脆不提供這個(gè) method 了,嘿嘿。

完整代碼

func main() {
	c := NewInfiniteChannel()
	go func() {
		for i := 0; i  20; i++ {
			c.In(i)
			time.Sleep(time.Second)
		}
		c.Close()
	}()

	for i := 0; i  50; i++ {
		val := c.Out()
		fmt.Print(val)
		time.Sleep(time.Millisecond * 500)
	}
}

type InfiniteChannel struct {
	inChan  chan interface{}
	outChan chan interface{}
	data    []interface{}
	isOpen  bool
}

func (c *InfiniteChannel) In(val interface{}) {
	c.inChan - val
}

func (c *InfiniteChannel) Out() interface{} {
	return -c.outChan
}

func (c *InfiniteChannel) Close() {
	close(c.inChan)
}

func (c *InfiniteChannel) background() {
	for true {
		select {
		case newVal, isOpen := -c.inChan:
			if isOpen {
				c.data = append(c.data, newVal)
			} else {
				c.isOpen = false
			}
		case c.outChanWrapper() - c.pop():
		}
	}
}

func NewInfiniteChannel() *InfiniteChannel {
	c := InfiniteChannel{
		inChan:  make(chan interface{}),
		outChan: make(chan interface{}),
		isOpen:  true,
	}
	go c.background()
	return c
}

// 取出隊(duì)列的首個(gè)元素,如果隊(duì)列為空,將會(huì)返回一個(gè) nil
func (c *InfiniteChannel) pop() interface{} {
	if len(c.data) == 0 {
		return nil
	}
	val := c.data[0]
	c.data = c.data[1:]
	return val
}

func (c *InfiniteChannel) outChanWrapper() chan interface{} {
	if c.isOpen  len(c.data) == 0 {
		return nil
	}
	return c.outChan
}

參考

https://medium.com/capital-one-tech/building-an-unbounded-channel-in-go-789e175cd2cd

以上就是再次探討go實(shí)現(xiàn)無(wú)限 buffer 的 channel方法的詳細(xì)內(nèi)容,更多關(guān)于go無(wú)限 buffer 的 channel的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

您可能感興趣的文章:
  • Go語(yǔ)言中使用 buffered channel 實(shí)現(xiàn)線(xiàn)程安全的 pool
  • go原生庫(kù)的中bytes.Buffer用法
  • C#語(yǔ)言使用gRPC、protobuf(Google Protocol Buffers)實(shí)現(xiàn)文件傳輸功能
  • 詳解Django-channels 實(shí)現(xiàn)WebSocket實(shí)例
  • Django使用Channels實(shí)現(xiàn)WebSocket的方法
  • Django Channels 實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)實(shí)時(shí)聊天和消息推送功能

標(biāo)簽:張掖 嘉峪關(guān) 宜賓 新余 黑龍江 武漢 江西 延邊

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《再次探討go實(shí)現(xiàn)無(wú)限 buffer 的 channel方法》,本文關(guān)鍵詞  再次,探討,實(shí)現(xiàn),無(wú)限,buffer,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《再次探討go實(shí)現(xiàn)無(wú)限 buffer 的 channel方法》相關(guān)的同類(lèi)信息!
  • 本頁(yè)收集關(guān)于再次探討go實(shí)現(xiàn)無(wú)限 buffer 的 channel方法的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    久久女同互慰一区二区三区| 日本韩国欧美三级| 一二三四区精品视频| 国产精品欧美极品| 日韩av在线发布| 国产亚洲精久久久久久| 色婷婷亚洲综合| 99视频超级精品| 91色porny蝌蚪| 成人白浆超碰人人人人| 在线观看日韩一区| 日韩精品一区二区三区四区视频| 91久久一区二区| 欧美伊人精品成人久久综合97| 久久久久国产精品麻豆| 欧美亚洲自拍偷拍| 日韩三级伦理片妻子的秘密按摩| 精品噜噜噜噜久久久久久久久试看| 日韩精品专区在线影院重磅| 亚洲精品第1页| 无码av中文一区二区三区桃花岛| 国产在线一区观看| 欧美中文字幕一区| 麻豆久久一区二区| 日韩精品一区二区三区中文精品 | 欧美日韩欧美一区二区| 在线观看一区日韩| 欧美一区二区三区在线观看视频| 国产日韩综合av| 国产精品青草综合久久久久99| 秋霞电影一区二区| 91久久精品网| 亚洲欧美色综合| 91原创在线视频| 国产精品久久久久aaaa樱花| 国精产品一区一区三区mba视频| 欧美一区二区在线免费观看| 久久久久久久久久久久久夜| 久99久精品视频免费观看| 欧美tickling挠脚心丨vk| 日韩电影免费一区| 欧美人狂配大交3d怪物一区| 亚洲专区一二三| 在线不卡欧美精品一区二区三区| 亚洲国产欧美在线人成| 欧美一区二区视频网站| 日本最新不卡在线| 久久美女高清视频| 成人高清视频免费观看| 亚洲伦理在线精品| 777奇米成人网| 国产高清精品网站| 亚洲柠檬福利资源导航| 欧美年轻男男videosbes| 一区二区三区四区精品在线视频| 精品国产sm最大网站免费看 | 亚洲一二三四在线| 精品视频一区三区九区| 亚洲精品视频在线观看网站| 91精品国产综合久久精品app| 久久成人麻豆午夜电影| 欧美成人a视频| 亚洲精品在线三区| www.亚洲国产| 麻豆一区二区99久久久久| 欧美一级精品大片| 日本精品一级二级| 另类中文字幕网| 亚洲三级久久久| 韩国v欧美v日本v亚洲v| 中文字幕亚洲视频| 9191久久久久久久久久久| 色国产综合视频| 成人高清视频免费观看| 成人av在线影院| 成人精品视频一区二区三区尤物| 日本sm残虐另类| 亚洲毛片av在线| 欧美亚洲综合一区| 欧美性猛交xxxxxxxx| 欧美日韩激情一区二区三区| 99riav一区二区三区| 欧美aaaaaa午夜精品| 国产又黄又大久久| 欧美肥大bbwbbw高潮| 91色在线porny| 欧美亚洲自拍偷拍| 亚洲综合丝袜美腿| 色综合天天综合色综合av| 国产成人精品综合在线观看| 国产乱码精品一区二区三区五月婷| 国产精品一区二区在线播放| 亚洲综合在线电影| 中文一区二区完整视频在线观看| 日本一区二区成人在线| 国产69精品久久777的优势| 欧美极品另类videosde| 精品在线一区二区三区| 亚洲精品国产第一综合99久久 | 久久精品国产精品亚洲精品 | 91亚洲国产成人精品一区二三| 日本aⅴ精品一区二区三区| 极品瑜伽女神91| 国产成人在线免费观看| 在线观看日韩毛片| 91国偷自产一区二区三区成为亚洲经典| 国产一区二区在线观看免费| 国产麻豆精品视频| 欧美一区二区成人6969| 成人黄色在线看| 天涯成人国产亚洲精品一区av| 色综合一区二区三区| 首页国产欧美日韩丝袜| 一区二区在线免费观看| 亚洲一区二区高清| 亚洲视频免费在线| 日本一区中文字幕| 欧美成人aa大片| 亚洲欧美一区二区在线观看| 欧美精品一区二区高清在线观看| 国产精品免费久久久久| 中文字幕免费不卡在线| 狠狠色丁香婷婷综合| aaa欧美色吧激情视频| 亚洲一区二区欧美激情| 精品国精品自拍自在线| 91精品国产综合久久精品性色| 久久久综合精品| 日韩avvvv在线播放| 久久av资源网| 91亚洲午夜精品久久久久久| 欧美人牲a欧美精品| 国产成人免费视频一区| 一区二区三区四区在线播放 | 免费成人在线观看视频| 精品国产污网站| 一区二区视频在线看| 一区二区三区日韩欧美| 国产精品一区三区| 91麻豆精品在线观看| 极品尤物av久久免费看| 毛片不卡一区二区| 青青草97国产精品免费观看无弹窗版 | 91麻豆精品国产91久久久久久久久| 国产精品丝袜久久久久久app| 国产xxx精品视频大全| 国产一区二区在线观看视频| 成人一区二区三区中文字幕| 精久久久久久久久久久| 欧美日产国产精品| 最新日韩在线视频| 成人动漫一区二区在线| 蜜桃精品视频在线| 亚洲国产美女搞黄色| 成人免费在线播放视频| 91小视频免费看| 亚洲欧美激情在线| 91精品国产aⅴ一区二区| 日韩精彩视频在线观看| 欧美日韩视频第一区| 欧美日韩在线观看一区二区| 成人黄色一级视频| 综合久久久久综合| 秋霞国产午夜精品免费视频| 成人在线视频一区二区| 色伊人久久综合中文字幕| 亚洲国产色一区| 欧美精品v国产精品v日韩精品| 欧美成人乱码一区二区三区| 亚洲一区二区综合| 欧美精品v国产精品v日韩精品| 精品一区二区三区在线观看| 亚洲一本大道在线| 国产一区二区久久| 中文字幕亚洲电影| 日韩一区二区三区电影在线观看 | 91国模大尺度私拍在线视频| 久久99精品国产| 91精品国产91综合久久蜜臀| 一区二区三区丝袜| 亚洲18女电影在线观看| 国产精品日产欧美久久久久| 国产精品污网站| 国产成人夜色高潮福利影视| 精品久久久久久亚洲综合网| 麻豆成人免费电影| 91.麻豆视频| 欧美电影在哪看比较好| 日韩一级在线观看| 欧美在线色视频| 欧美国产乱子伦| 日韩和欧美一区二区| 欧美综合天天夜夜久久| 亚洲欧美日韩小说| 亚洲第一福利视频在线| 久久久蜜桃精品| 欧洲av在线精品| 国产亚洲污的网站| 成人的网站免费观看| 精品午夜一区二区三区在线观看|