佳木斯湛栽影视文化发展公司

主頁(yè) > 知識(shí)庫(kù) > 使用Go語(yǔ)言簡(jiǎn)單模擬Python的生成器

使用Go語(yǔ)言簡(jiǎn)單模擬Python的生成器

熱門標(biāo)簽:鐵路電話系統(tǒng) 百度競(jìng)價(jià)排名 地方門戶網(wǎng)站 呼叫中心市場(chǎng)需求 網(wǎng)站排名優(yōu)化 服務(wù)外包 Linux服務(wù)器 AI電銷
def demo_input_and_output():
  input = yield 'what is the input?'
  yield 'input is: %s' % input

gen = demo_input_and_output()
print(gen.next())
print(gen.send(42))

這段代碼演示了 python generator 的功能??梢钥吹?yield 同時(shí)做了兩個(gè)操作,一個(gè)是往外發(fā)數(shù)據(jù) "waht is the input",同時(shí)做的操作是往里收數(shù)據(jù) input。而且這個(gè)接收數(shù)據(jù)的操作是一個(gè)阻塞的操作,如果外部沒(méi)有調(diào)用 next() (也就是往里傳遞None),或者調(diào)用send(42)(也就是往里傳遞42這個(gè)值),那么這個(gè)阻塞的操作就會(huì)一直等待下去。

也就是說(shuō) python 的 generator 自帶了一個(gè)對(duì)外通信的 channel,用于收發(fā)消息。用 go 模擬 python 的 generator 的話寫(xiě)起來(lái)就是這樣的

復(fù)制代碼 代碼如下:
package main

import "fmt"

func demoInputAndOutput(channel chan string) {
    channel - "what is my input?"
    input := - channel
    channel - fmt.Sprintf("input is: %s", input)
}

func main() {
    channel := make(chan string)
    go demoInputAndOutput(channel)
    fmt.Println(- channel)
    channel - "42"
    fmt.Println(- channel)
}

這段代碼和 python 版本基本上等價(jià)。隱含的 channel 在 go 版本里變成顯式的了。yield 變成了 channel - 操作,同時(shí)立馬做了一個(gè) - channel 的阻塞讀操作。這也就是 yield 的本質(zhì)吧。

go 的 channel 也可以當(dāng)成 iterator 被 for 循環(huán)使用:

復(fù)制代碼 代碼如下:
package main

import "fmt"

func someGenerator() -chan string {
    channel := make(chan string)
    go func() {
        channel - "a"
        fmt.Println("after a")
        channel - "c"
        fmt.Println("after c")
        channel - "b"
        fmt.Println("after b")
        close(channel)
    }()
    return channel
}

func main() {
    channel := someGenerator()
    for val := range channel {
        fmt.Println(val)
    }
}

和 python 的 yield 不同,這里的 channel - 不等價(jià)于 yield,它會(huì)往下執(zhí)行直到阻塞。效果是

復(fù)制代碼 代碼如下:
after a
a
c
after c
after b
b

這和預(yù)期的順序不一樣。這里沒(méi)有把 after a after c after b 都打印出來(lái)是因?yàn)?channel 默認(rèn)只有一個(gè)元素的buffer,所以寫(xiě)入了一個(gè)就阻塞了。如果增大 buffer,那么就有效果了

復(fù)制代碼 代碼如下:
make(chan string, 10)

輸出變成了:

after a
after c
after b
a
c
b

可見(jiàn) goroutine 就好象一個(gè)獨(dú)立的線程一樣自己和自己玩去了,不用等待被執(zhí)行。如果要模擬 yield 就要加上顯示的同步操作(從 channel 里阻塞讀取信號(hào)):

復(fù)制代碼 代碼如下:
package main

import "fmt"

func someGenerator() chan string {
    channel := make(chan string)
    go func() {
        channel - "a"
        - channel
        fmt.Println("after a")
        channel - "c"
        - channel
        fmt.Println("after c")
        channel - "b"
        - channel
        fmt.Println("after b")
        close(channel)
    }()
    return channel
}

func main() {
    channel := someGenerator()
    for val := range channel {
        fmt.Println(val)
        channel - ""
    }
}

輸出的結(jié)果就是

a
after a
c
after c
b
after b

到這里我們可以看到,python 的 generator 就好象是 golang 的 goroutine 帶了一個(gè)無(wú)buffer的channel。這樣導(dǎo)致每次yield一個(gè)值,都會(huì)產(chǎn)生一次協(xié)程上下文切換。雖然協(xié)程上下文切換很廉價(jià),但是也不是沒(méi)有成本。像 goroutine 的 buffered channel 這樣的設(shè)計(jì),可以讓一個(gè) goroutine 一次性多產(chǎn)生一些輸出再阻塞等待,而不是產(chǎn)生一個(gè)輸出就阻塞等待一下,再產(chǎn)生另外一個(gè)輸出。golang rocks!

您可能感興趣的文章:
  • golang、python、php、c++、c、java、Nodejs性能對(duì)比
  • 詳解Golang 與python中的字符串反轉(zhuǎn)
  • Golang與python線程詳解及簡(jiǎn)單實(shí)例
  • C++、python和go語(yǔ)言實(shí)現(xiàn)的簡(jiǎn)單客戶端服務(wù)器代碼示例
  • Python和GO語(yǔ)言實(shí)現(xiàn)的消息摘要算法示例
  • Golang如何調(diào)用Python代碼詳解

標(biāo)簽:黃山 蘭州 銅川 仙桃 湖南 崇左 衡水 湘潭

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《使用Go語(yǔ)言簡(jiǎn)單模擬Python的生成器》,本文關(guān)鍵詞  ;如發(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)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    和龙市| 宁强县| 乌拉特前旗| 永川市| 许昌县| 焦作市| 晋中市| 永宁县| 金门县| 都匀市| 大同市| 东方市| 剑河县| 花莲县| 秦皇岛市| 剑川县| 紫阳县| 石景山区| 望江县| 太康县| 泰顺县| 胶州市| 孟州市| 福鼎市| 安国市| 庆阳市| 贵州省| 方城县| 康保县| 沾益县| 昌乐县| 门源| 会理县| 慈溪市| 青神县| 新泰市| 永平县| 宣武区| 页游| 汽车| 中阳县|