• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >Golang > 使用Go语言简单模拟Python的生成器

使用Go语言简单模拟Python的生成器

作者: 字体:[增加 减小] 来源:互联网

通过本文主要向大家介绍了go语言和python,go python,go语言菜鸟教程,go语言下载,go语言等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com
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))

</div>

这段代码演示了 python generator 的功能。可以看到 yield 同时做了两个操作,一个是往外发数据 "waht is the input",同时做的操作是往里收数据 input。而且这个接收数据的操作是一个阻塞的操作,如果外部没有调用 next() (也就是往里传递None),或者调用send(42)(也就是往里传递42这个值),那么这个阻塞的操作就会一直等待下去。

也就是说 python 的 generator 自带了一个对外通信的 channel,用于收发消息。用 go 模拟 python 的 generator 的话写起来就是这样的

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)
}</div>

这段代码和 python 版本基本上等价。隐含的 channel 在 go 版本里变成显式的了。yield 变成了 channel <- 操作,同时立马做了一个 <- channel 的阻塞读操作。这也就是 yield 的本质吧。

go 的 channel 也可以当成 iterator 被 for 循环使用:

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)
    }
}</div>

和 python 的 yield 不同,这里的 channel <- 不等价于 yield,它会往下执行直到阻塞。效果是

a
c
after c
after b
b</div>

这和预期的顺序不一样。这里没有把 after a after c after b 都打印出来是因为 channel 默认只有一个元素的buffer,所以写入了一个就阻塞了。如果增大 buffer,那么就有效果了

输出变成了:

after a
after c
after b
a
c
b

</div>

可见 goroutine 就好象一个独立的线程一样自己和自己玩去了,不用等待被执行。如果要模拟 yield 就要加上显示的同步操作(从 channel 里阻塞读取信号):

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 <- ""
    }
}</div>

输出的结果就是

a
after a
c
after c
b
after b

</div>

到这里我们可以看到,python 的 generator 就好象是 golang 的 goroutine 带了一个无buffer的channel。这样导致每次yield一个值,都会产生一次协程上下文切换。虽然协程上下文切换很廉价,但是也不是没有成本。像 goroutine 的 buffered channel 这样的设计,可以让一个 goroutine 一次性多产生一些输出再阻塞等待,而不是产生一个输出就阻塞等待一下,再产生另外一个输出。golang rocks!

</div>

您可能想查找下面的文章:

  • 使用Go语言简单模拟Python的生成器
  • Go语言压缩和解压缩tar.gz文件的方法

相关文章

  • 深入理解Go语言中的闭包
  • Centos下搭建golang环境及vim高亮Go关键字设置的方法
  • GO语言实现简单TCP服务的方法
  • Go实现比较时间大小
  • Golang中channel使用的一些小技巧
  • golang守护进程用法示例
  • golang简单tls协议用法完整示例
  • Go语言结构体定义和使用方法
  • go语言使用RC4加密的方法
  • Go语言MD5加密用法实例

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • Golang记录、计算函数执行耗时、运行时间的一个简单方法
    • 浅谈Go语言的空标示符
    • Golang学习笔记(二):类型、变量、常量
    • go语言简单的处理http请求的函数实例
    • go语言按显示长度截取字符串的方法
    • GO语言标准错误处理机制error用法实例
    • Go语言运行环境安装详细教程
    • go语言执行等待直到后台goroutine执行完成实例分析
    • Go语言导出内容到Excel的方法
    • go语言异常panic和恢复recover用法实例

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有