是否有一个简单的程序来演示Go中队列的工作方式。 我只需要在队列中添加1到10之类的东西,并使用另一个线程并行地从队列中拉出那些。
答案 0 :(得分:7)
对于并发使用安全的队列基本上是一种语言构造:channel。
渠道设计 - 对于并发send和receive是安全的。这是详细信息:If I am using channels properly should I need to use mutexes?在其上发送的值按发送顺序接收。
您可以在此处详细了解频道:What are golang channels used for?
一个非常简单的例子:
c := make(chan int, 10) // buffer for 10 elements
// Producer: send elements in a new goroutine
go func() {
for i := 0; i < 10; i++ {
c <- i
}
close(c)
}()
// Consumer: receive all elements sent on it before it was closed:
for v := range c {
fmt.Println("Received:", v)
}
输出(在Go Playground上尝试):
Received: 0
Received: 1
Received: 2
Received: 3
Received: 4
Received: 5
Received: 6
Received: 7
Received: 8
Received: 9
请注意,通道缓冲区(本例中为10)与要通过它“发送”的元素数无关。缓冲区告诉通道可以“存储”多少元素,换句话说,当没有人从中接收时,可以在没有阻塞的情况下发送多少元素。当通道的缓冲区已满时,进一步的发送将阻塞,直到有人开始从中接收值。
答案 1 :(得分:3)
您可以使用频道(安全用于并发使用)和等待组同时从队列中读取
package main
import (
"fmt"
"sync"
)
func main() {
queue := make(chan int)
wg := new(sync.WaitGroup)
wg.Add(1)
defer wg.Wait()
go func(wg *sync.WaitGroup) {
for {
r, ok := <-queue
if !ok {
wg.Done()
return
}
fmt.Println(r)
}
}(wg)
for i := 1; i <= 10; i++ {
queue <- i
}
close(queue)
}
答案 2 :(得分:0)
另一种选择是创建和实现队列interface
,其支持类型为并发通道。为方便起见,我做了gist。
以下是如何使用它。
queue := GetIntConcurrentQueue()
defer queue.Close()
// queue.Enqueue(1)
// myInt, errQueueClosed := queue.DequeueBlocking()
// myInt, errIfNoInt := queue.DequeueNonBlocking()
这里有更长的例子 - https://play.golang.org/p/npb2Uj9hGn1
下面的完整实现,这里再次是gist。
// Can be any backing type, even 'interface{}' if desired.
// See stackoverflow.com/q/11403050/3960399 for type conversion instructions.
type IntConcurrentQueue interface {
// Inserts the int into the queue
Enqueue(int)
// Will return error if there is nothing in the queue or if Close() was already called
DequeueNonBlocking() (int, error)
// Will block until there is a value in the queue to return.
// Will error if Close() was already called.
DequeueBlocking() (int, error)
// Close should be called with defer after initializing
Close()
}
func GetIntConcurrentQueue() IntConcurrentQueue {
return &intChannelQueue{c: make(chan int)}
}
type intChannelQueue struct {
c chan int
}
func (q *intChannelQueue) Enqueue(i int) {
q.c <- i
}
func (q *intChannelQueue) DequeueNonBlocking() (int, error) {
select {
case i, ok := <-q.c:
if ok {
return i, nil
} else {
return 0, fmt.Errorf("queue was closed")
}
default:
return 0, fmt.Errorf("queue has no value")
}
}
func (q *intChannelQueue) DequeueBlocking() (int, error) {
i, ok := <-q.c
if ok {
return i, nil
}
return 0, fmt.Errorf("queue was closed")
}
func (q *intChannelQueue) Close() {
close(q.c)
}