GCD串行调度队列的Go等效方式

huangapple go评论91阅读模式
英文:

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
}

playground

英文:

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&#39;t block, you can play with that to your liking.
	var wg sync.WaitGroup
	for i := 0; i &lt; 10; i++ {
		wg.Add(1)
		i := i
		q &lt;- func() { log.Println(&quot;i =&quot;, 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的类型,它表示一个串行调度队列。该类型包含两个通道成员变量taskQueuesyncChannel

NewSerialDispatchQueue函数用于创建一个新的SerialDispatchQueue实例。它初始化了taskQueuesyncChannel通道,并启动了一个无限循环的goroutine。在每次循环中,它从taskQueue通道接收一个函数并执行,然后向syncChannel通道发送一个空结构体。

Sync方法用于同步执行一个函数。它将函数发送到taskQueue通道,并等待从syncChannel通道接收到一个值,以确保函数执行完成。

Async方法用于异步执行一个函数。它将函数发送到taskQueue通道,但不等待函数执行完成。

这段代码实现了一个简单的串行调度队列,可以用于按顺序执行一系列函数。

英文:
type SerialDispatchQueue struct {
	taskQueue   chan func()
	syncChannel chan struct{}
}

func NewSerialDispatchQueue() *SerialDispatchQueue {
	m := &amp;SerialDispatchQueue{
		taskQueue:   make(chan func()),
		syncChannel: make(chan struct{}),
	}

	go func() {
		for {
			(&lt;-m.taskQueue)()
			m.syncChannel &lt;- struct{}{}
		}
	}()

	return m
}

func (m *SerialDispatchQueue) Sync(f func()) {
	m.taskQueue &lt;- f
	&lt;-m.syncChannel
}

func (m *SerialDispatchQueue) Async(f func()) {
	m.taskQueue &lt;- f
}

huangapple
  • 本文由 发表于 2016年1月21日 22:51:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/34926930.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定