Go基础 专题
专题目录
您的位置:go > Go基础 专题 > Go有状态的goroutines实例
Go有状态的goroutines实例
作者:--    发布时间:2019-11-20

在前面的示例中,我们使用显式锁定互斥体来同步对多个goroutine的共享状态的访问。 另一个选项是使用goroutine和通道的内置同步功能来实现相同的结果。这种基于通道的方法与go的共享内存的想法一致,通过沟通,拥有每个数据的goroutine恰好只有1个。

在这个例子中,状态将由单个goroutine拥有。这将保证数据不会因并发访问而损坏。为了读或写状态,其他goroutine将发送消息到拥有的goroutine并接收相应的回复。这些readopwriteop结构封装了这些请求,并拥有一个goroutine响应的方法。

和以前一样,我们将计算执行的操作数。

读写通道将被其他goroutine分别用来发出读和写请求。

这里是拥有状态的goroutine,它是一个如前面示例中的映射,但现在对状态goroutine是私有的。这个goroutine在读取和写入通道时重复选择,在请求到达时响应请求。 通过首先执行所请求的操作,然后在响应信道上发送值以指示成功(以及在读取的情况下的期望值)来执行响应。

这里启动了100goroutine来通过读取通道向状态拥有的goroutine发出读取。每次读取都需要构造一个readop,通过读取通道发送readop,并通过提供的resp通道接收结果。

也使用类似的方法开始10个写操作。让goroutine工作一秒钟。最后,捕获和报告操作计数。

运行程序显示,基于goroutine的状态管理示例程序,完成了大约80,000次操作。

对于这种特殊情况,基于goroutine的方法比基于互斥的方法更多一些。它在某些情况下可能是有用的,例如,当有其他通道涉及或管理多个此类互斥体将容易出错。应该使用最自然的方法,有助于理解程序。

所有的示例代码,都放在 f:\worksp\golang 目录下。安装go编程环境请参考:http://www.h3.com/go/go_environment.html

stateful-goroutines.go的完整代码如下所示 -

package main

import (
    "fmt"
    "math/rand"
    "sync/atomic"
    "time"
)

// in this example our state will be owned by a single
// goroutine. this will guarantee that the data is never
// corrupted with concurrent access. in order to read or
// write that state, other goroutines will send messages
// to the owning goroutine and receive corresponding
// replies. these `readop` and `writeop` `struct`s
// encapsulate those requests and a way for the owning
// goroutine to respond.
type readop struct {
    key  int
    resp chan int
}
type writeop struct {
    key  int
    val  int
    resp chan bool
}

func main() {

    // as before we'll count how many operations we perform.
    var readops uint64 = 0
    var writeops uint64 = 0

    // the `reads` and `writes` channels will be used by
    // other goroutines to issue read and write requests,
    // respectively.
    reads := make(chan *readop)
    writes := make(chan *writeop)

    // here is the goroutine that owns the `state`, which
    // is a map as in the previous example but now private
    // to the stateful goroutine. this goroutine repeatedly
    // selects on the `reads` and `writes` channels,
    // responding to requests as they arrive. a response
    // is executed by first performing the requested
    // operation and then sending a value on the response
    // channel `resp` to indicate success (and the desired
    // value in the case of `reads`).
    go func() {
        var state = make(map[int]int)
        for {
            select {
            case read := <-reads:
                read.resp <- state[read.key]
            case write := <-writes:
                state[write.key] = write.val
                write.resp <- true
            }
        }
    }()

    // this starts 100 goroutines to issue reads to the
    // state-owning goroutine via the `reads` channel.
    // each read requires constructing a `readop`, sending
    // it over the `reads` channel, and the receiving the
    // result over the provided `resp` channel.
    for r := 0; r < 100; r++ {
        go func() {
            for {
                read := &readop{
                    key:  rand.intn(5),
                    resp: make(chan int)}
                reads <- read
                <-read.resp
                atomic.adduint64(&readops, 1)
                time.sleep(time.millisecond)
            }
        }()
    }

    // we start 10 writes as well, using a similar
    // approach.
    for w := 0; w < 10; w++ {
        go func() {
            for {
                write := &writeop{
                    key:  rand.intn(5),
                    val:  rand.intn(100),
                    resp: make(chan bool)}
                writes <- write
                <-write.resp
                atomic.adduint64(&writeops, 1)
                time.sleep(time.millisecond)
            }
        }()
    }

    // let the goroutines work for a second.
    time.sleep(time.second)

    // finally, capture and report the op counts.
    readopsfinal := atomic.loaduint64(&readops)
    fmt.println("readops:", readopsfinal)
    writeopsfinal := atomic.loaduint64(&writeops)
    fmt.println("writeops:", writeopsfinal)
}

执行上面代码,将得到以下输出结果 -

f:\worksp\golang>go run mutexes.go
readops: 84546
writeops: 8473
state: map[0:99 3:3 4:62 1:18 2:89]

网站声明:
本站部分内容来自网络,如您发现本站内容
侵害到您的利益,请联系本站管理员处理。
联系站长
373515719@qq.com
关于本站:
编程参考手册