最常用的同时写入和读取数组的方式

时间:2014-07-15 06:28:48

标签: io go goroutine

我有一个数组每秒被修改几次,只有一个goroutine。在另一个函数中,我每隔几秒就从数组中读取一个随机值。接近这个问题的最像Go的方式是什么?

例如,在Java中,我会首先锁定数组,然后从中读取数据。我不确定我是否可以使用通道,因为我不想等到我的其他函数读取才能继续更新数组。

package main

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

const (
    SliceLength = 32
)

var mySlice []int

func randInt(min int, max int) int {
    return min + rand.Intn(max-min)
}

func writeSlice() {
    for index, _ := range mySlice {
        mySlice[index] = rand.Intn(100)
    }
}

func main() {
    rand.Seed(time.Now().UnixNano())
    mySlice = make([]int, SliceLength)

    // First time just to populate it.
    writeSlice()

    // Write to the slice.
    go func() {
        for {
            time.Sleep(time.Duration(randInt(10, 50)) * time.Millisecond)
            writeSlice()
        }
    }()

    // Read from slice.
    for {
        time.Sleep(time.Duration(randInt(1, 5)) * time.Second)
        fmt.Println(mySlice[randInt(0, SliceLength)])
    }
}

2 个答案:

答案 0 :(得分:1)

互斥sync.RWMutex可以在这里工作。您只需在两个goroutine之间共享切片,在每次切片操作之前/之后锁定和释放。

虽然您正在探索各种可能性,但您还应该考虑" shared-nothing "原则意味着。您可能希望找到一个不使用互斥锁的解决方案,其中每个goroutine只有私有数据 - 无共享。

假设你有第三个goroutine。把它想象成一个服务器。它保存切片(或任何其他所需的竞争数据结构)。当您的第一个goroutine想要进行更改时,它会在通道上向服务器发送一条消息,说"将x更改为y"。当您的第二个goroutine想要读取数据时,它可能只是从来自服务器的通道中读取数据的副本。

在服务器内部,select语句将在传入更新消息和传出读取消息之间进行选择 - 请记住,警卫可以在通道输入或通道输出上,因此这很容易做到。

...  declare and initialise the slice
for {
    select {
    case instruction = <-update:
        ...  apply the instruction to the slice
    case output<- slice:
        ...  sent the slice to the consumer
    }
}

请注意,服务器代码本身是单线程,即切片没有共享内存访问权限,即使整体行为是并发的。这是CSP方法的一个很好的特性:在本地,从不需要担心共享数据访问。 &#34;无共享&#34;意味着什么。

此外,您可以在本地完全推断出这样一段代码的可能状态,而无需全局知识。这是一个很大的好处。

答案 1 :(得分:0)

听起来像是sync.RWMutex的工作。

  

RWMutex是读/写互斥锁。锁可以由任意数量的读者或单个作者持有。 RWMutexes可以作为其他结构的一部分创建; RWMutex的零值是一个未锁定的互斥锁。