英文:
Go equivalent of GCD serial dispatch queue
问题
有没有Go语言的等效方法来实现苹果的GCD串行调度队列?
到目前为止,我只找到了一个使用函数通道的解决方案。
work := make(chan func())
我希望一个函数从这个通道接收并调用接收到的函数。这些函数必须按照FIFO顺序执行。
在Go语言中有更好的方法或结构来实现这个吗?
这可能不会有什么区别,但我想按照FIFO顺序排队SQL查询以运行。
英文:
Is there Go equivalent of Apple's GCD serial dispatch queue?
So far I have only found a solution that is a channel of functions.
work := make(chan func())
I would have a function receive from this channel and call the received functions. The functions must be executed in FIFO order.
Is there a better method or structure to do this in Go?
This shouldn't make a difference but I am looking to queue SQL queries to run in FIFO for this.
答案1
得分: 2
@OneOfOne,它接近但不完全相同。
我最终在Go中实现了一个串行调度队列,可以在这里找到。
它基本上是一个阻塞在类型为func()
的channel
上的Go协程,并按顺序运行传入的函数。
实现:
//Package serialqueue provides a serial queue for functions.
//Queue items are processed in First In First Out (FIFO) order.
package serialqueue
//New returns a new serial queue.
//Enqueue items like queueObj <- func() {doWork(data)}
func New() chan func() {
//create channel of type function
var queue = make(chan func())
//spawn go routine to read and run functions in the channel
go func() {
for true {
nextFunction := <-queue
nextFunction()
}
}()
return queue
}
用法:(演示按正确顺序写入字符串)
//Package serialqueue provides provides tests for github.com/ansonl/serialqueue.
package serialqueue_test
import (
"testing"
"fmt"
"sync"
"github.com/ansonl/serialqueue"
)
func TestQueue(t *testing.T) {
//Create new serial queue
queue := serialqueue.New()
//Number of times to loop
var loops = 100
//Queue output will be added here
var queueOutput string
//WaitGroup for determining when queue output is finished
var wg sync.WaitGroup
//Create function to place in queue
var printTest = func(i int) {
queueOutput = fmt.Sprintf("%v%v",queueOutput, i)
wg.Done()
}
//Add functions to queue
var i int;
for i=0;i<loops;i++ {
wg.Add(1)
t:=i
queue <- func() {printTest(t)}
}
//Generate correct output
var correctOutput string
for i=0;i<loops;i++ {
correctOutput = fmt.Sprintf("%v%v", correctOutput, i)
}
//Wait until all functions in queue are done
wg.Wait()
//Compare queue output with correct output
if queueOutput != correctOutput {
t.Errorf("Serial Queue produced %v, want %v", queueOutput, correctOutput);
}
}
希望这对有同样问题的人有所帮助!
英文:
@OneOfOne, it was close but not quite.
I ended up making a Serial Dispatch Queue implementation in Go available here.
It is basically a go routine that blocks on a channel
of type func()
and runs the functions that are passed in order.
Implementation:
//Package serialqueue provides a serial queue for functions.
//Queue items are processed in First In First Out (FIFO) order.
package serialqueue
//New returns a new serial queue.
//Enqueue items like queueObj <- func() {doWork(data)}
func New() chan func() {
//create channel of type function
var queue = make(chan func())
//spawn go routine to read and run functions in the channel
go func() {
for true {
nextFunction := <-queue
nextFunction()
}
}()
return queue
}
Usage: (demonstrating writing to a string in the correct order)
//Package serialqueue provides provides tests for github.com/ansonl/serialqueue.
package serialqueue_test
import (
"testing"
"fmt"
"sync"
"github.com/ansonl/serialqueue"
)
func TestQueue(t *testing.T) {
//Create new serial queue
queue := serialqueue.New()
//Number of times to loop
var loops = 100
//Queue output will be added here
var queueOutput string
//WaitGroup for determining when queue output is finished
var wg sync.WaitGroup
//Create function to place in queue
var printTest = func(i int) {
queueOutput = fmt.Sprintf("%v%v",queueOutput, i)
wg.Done()
}
//Add functions to queue
var i int;
for i=0;i<loops;i++ {
wg.Add(1)
t:=i
queue <- func() {printTest(t)}
}
//Generate correct output
var correctOutput string
for i=0;i<loops;i++ {
correctOutput = fmt.Sprintf("%v%v", correctOutput, i)
}
//Wait until all functions in queue are done
wg.Wait()
//Compare queue output with correct output
if queueOutput != correctOutput {
t.Errorf("Serial Queue produced %v, want %v", queueOutput, correctOutput);
}
}
Hope this helps someone with the same issue!
答案2
得分: 0
像这样应该可以工作,但是我对GCD的工作原理不熟悉,所以可能有些偏差。
func main() {
q := NewQueue(10) // size主要是为了避免阻塞,你可以根据需要进行调整。
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
i := i
q <- func() { log.Println("i =", i); wg.Done() }
}
wg.Wait()
close(q)
}
func NewQueue(size int) (q chan func()) {
q = make(chan func(), size)
go func() {
for fn := range q {
fn()
}
}()
return
}
英文:
Something like this should work, however I'm not familiar with how GCD works so I could be way off.
func main() {
q := NewQueue(10) // the size is mainly so it wouldn't block, you can play with that to your liking.
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
i := i
q <- func() { log.Println("i =", i); wg.Done() }
}
wg.Wait()
close(q)
}
func NewQueue(size int) (q chan func()) {
q = make(chan func(), size)
go func() {
for fn := range q {
fn()
}
}()
return
}
<kbd>playground</kbd>
答案3
得分: 0
type SerialDispatchQueue struct {
taskQueue chan func()
syncChannel chan struct{}
}
func NewSerialDispatchQueue() *SerialDispatchQueue {
m := &SerialDispatchQueue{
taskQueue: make(chan func()),
syncChannel: make(chan struct{}),
}
go func() {
for {
(<-m.taskQueue)()
m.syncChannel <- struct{}{}
}
}()
return m
}
func (m *SerialDispatchQueue) Sync(f func()) {
m.taskQueue <- f
<-m.syncChannel
}
func (m *SerialDispatchQueue) Async(f func()) {
m.taskQueue <- f
}
这段代码定义了一个名为SerialDispatchQueue
的类型,它表示一个串行调度队列。该类型包含两个通道成员变量taskQueue
和syncChannel
。
NewSerialDispatchQueue
函数用于创建一个新的SerialDispatchQueue
实例。它初始化了taskQueue
和syncChannel
通道,并启动了一个无限循环的goroutine。在每次循环中,它从taskQueue
通道接收一个函数并执行,然后向syncChannel
通道发送一个空结构体。
Sync
方法用于同步执行一个函数。它将函数发送到taskQueue
通道,并等待从syncChannel
通道接收到一个值,以确保函数执行完成。
Async
方法用于异步执行一个函数。它将函数发送到taskQueue
通道,但不等待函数执行完成。
这段代码实现了一个简单的串行调度队列,可以用于按顺序执行一系列函数。
英文:
type SerialDispatchQueue struct {
taskQueue chan func()
syncChannel chan struct{}
}
func NewSerialDispatchQueue() *SerialDispatchQueue {
m := &SerialDispatchQueue{
taskQueue: make(chan func()),
syncChannel: make(chan struct{}),
}
go func() {
for {
(<-m.taskQueue)()
m.syncChannel <- struct{}{}
}
}()
return m
}
func (m *SerialDispatchQueue) Sync(f func()) {
m.taskQueue <- f
<-m.syncChannel
}
func (m *SerialDispatchQueue) Async(f func()) {
m.taskQueue <- f
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论