如何把golang的Channel玩出async和await的feel

栏目: IT技术 · 发布时间: 4年前

内容简介:如何优雅的同步化异步代码,一直以来都是各大编程语言致力于优化的点,记得最早是C# 5.0加入了async/await来简化TPL的多线程模型,后来Javascript的Promise也吸取这一语法糖,在ES 6中也加入了async和await.那么,被大家一称赞并发性能好、异步模型独树一帜的golang,能否也有async和await呢?其实,这对于golang的CSM来说是一点也不难!

如何优雅的同步化异步代码,一直以来都是各大编程语言致力于优化的点,记得最早是C# 5.0加入了async/await来简化TPL的多线程模型,后来Javascript的Promise也吸取这一语法糖,在ES 6中也加入了async和await.

那么,被大家一称赞并发性能好、异步模型独树一帜的golang,能否也有async和await呢?

其实,这对于golang的CSM来说是一点也不难!

核心代码如下:

done := make(chan struct{})
go func() {
	// do work asynchronously here
	//
	close(done)
}()
<-done
复制代码

是不是很简单呢? go rountine负责async, channel的负责await, 简直是完美!

但这个代码看起来还是有点丑,而且这个 go func(){} 还没有返回值,虽说可以通过闭包来接收返回值,但那个代码就更难维护了。

Go Promise

代码难看不要紧,只要Don't repeat yourself (DRY),封装一下不就好了?

type WorkFunc func() (interface{}, error)

func NewPromise(workFunc WorkFunc) *Promise {
	promise := Promise{done: make(chan struct{})}
	go func() {
		defer close(promise.done)
		promise.res, promise.err = workFunc()
	}()
	return &promise
}

func (p *Promise) Done() (interface{}, error) {
	<-p.done
	return p.res, p.err
}
复制代码

调用的代码如下:

promise := NewPromise(func() (interface{}, error) {
	// do work asynchronously here
	//
	return res, err
})

// await
res, err := promise.Done()
复制代码

是不是美观了许多呢?

这个实现和Javascript的Promise的API是有很大差距,使用体验上因为golang没有泛型,也需要转来转去的,但为了不辜负Promise这个名字,怎么能没有 then 呢?

type SuccessHandler func(interface{}) (interface{}, error)

type ErrorHandler func(error) interface{}

func (p *Promise) Then(successHandler SuccessHandler, errorHandler ErrorHandler) *Promise {
	newPromise := &Promise{done: make(chan struct{})}
	go func() {
		res, err := p.Done()
		defer close(newPromise.done)
		if err != nil {
			if errorHandler != nil {
				newPromise.res = errorHandler(err)
			} else {
				newPromise.err = err
			}
		} else {
			if successHandler != nil {
				newPromise.res, newPromise.err = successHandler(res)
			} else {
				newPromise.res = res
			}
		}
	}()

	return newPromise
}
复制代码

有了 then 可以chain起来,是不是找到些Promise的感觉呢?

完整代码请查看 promise.go

Actor

本来我的理解也就到些了,然后前段时间( 说来也是一月有余了 ),看了 Go并发 设计模式 之 Active Object 这篇文章后, 发现如果有一个常驻协程在异步的处理任务,而且是FIFO的,那么这其实是相当于一个无锁的设计,可以简化对临界资源的操作。

于是,我照着文章的思路,实现了下面的代码:

// Creates a new actor
func NewActor(setActorOptionFuncs ...SetActorOptionFunc) *Actor {
	actor := &Actor{buffer: runtime.NumCPU(), quit: make(chan struct{}), wg: &sync.WaitGroup{}}
	for _, setOptionFunc := range setActorOptionFuncs {
		setOptionFunc(actor)
	}

	actor.queue = make(chan request, actor.buffer)

	actor.wg.Add(1)
	go actor.schedule()

	return actor
}

// The long live go routine to run.
func (actor *Actor) schedule() {
loop:
	for {
		select {
		case request := <-actor.queue:
			request.promise.res, request.promise.err = request.work()
			close(request.promise.done)
		case <-actor.quit:
			break loop
		}
	}
	actor.wg.Done()
}

// Do a work.
func (actor *Actor) Do(workFunc WorkFunc) *Promise {
	methodRequest := request{work: workFunc, promise: &Promise{
		done: make(chan struct{}),
	}}
	actor.queue <- methodRequest
	return methodRequest.promise
}

// Close actor
func (actor *Actor) Close() {
	close(actor.quit)
	actor.wg.Wait()
}
复制代码

一个简单的没啥意义的纯粹为了demo的测试用例如下:

func TestActorAsQueue(t *testing.T) {
	actor := NewActor()
	defer actor.Close()

	i := 0
	workFunc := func() (interface{}, error) {
		time.Sleep(1 * time.Second)
		i++
		return i, nil
	}

	promise := actor.Do(workFunc)
	promise2 := actor.Do(workFunc)

	res2, _ := promise2.Done()
	res1, _ := promise.Done()

	if res1 != 1 {
		t.Fail()
	}

	if res2 != 2 {
		t.Fail()
	}
}
复制代码

完整代码请查看 actor.go

总结

每个语言都有它的独特之处,在我的理解中,玩转golang的CSM模型,channel一定要用的6。

于是,我创建了 Channelx 这个repo, 包含了对channel常用场景的封装,欢迎大家审阅,喜欢的就点个star。


以上所述就是小编给大家介绍的《如何把golang的Channel玩出async和await的feel》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

微机原理与接口技术

微机原理与接口技术

李文英、李勤、刘星、宋蕴新 / 清华大学出版社 / 2001-9 / 26.00元

《高等院校计算机应用技术规划教材•应用型教材系列•微机原理与接口技术》是“高职高专计算机系列教材”之一。全书包括微机原理、汇编语言、接口技术三部分内容。微机原理部分讲述了80x86的内部结构及工作原理、半导体存储器及其系统、微型机总线结构等。汇编语言部分讲述了指令系统、编程技巧。接口技术部分讲述了中断系统、中断控制器、并行接口、串行接口、DMA控制器、定时器,以及A/D、D/A转换器等常用芯片的硬......一起来看看 《微机原理与接口技术》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具