用Go中的渠道实现承诺

问题描述 投票:7回答:4

我正在尝试在Go中实现Promise,这与Javascript中的类似。

type Promise struct {
        Result chan string
        Error  chan error
}

func NewPromise() (*Promise) {
        r := make(chan string, 1)
        e := make(chan error, 1)
        return &Promise{
                Result: r,
                Error:  e,
        }
}

func main() {
        var p = NewPromise()

        go func(p *Promise) {
                time.Sleep(time.Duration(5)*time.Second)
                p.Result <- "done"
        }(p)

        if <- p.Result {
                fmt.Println(<-p.Result)
        }

        // Is it possible to do something else here while wait for 5s?

        // Once Promise is fulfilled after 5s, the Result is available.
}

我该怎么做:

  1. 运行goroutine,立即将Promise返回主goroutine。
  2. 异步地在主程序上执行某些操作,同时等待将任何内容发送到Promise.ResultPromise.Error
  3. 发送一些内容后,从goroutine返回并使该频道可供阅读。
asynchronous go promise channel
4个回答
15
投票

不使用通道的不同方法,使其更快/更高效:

type Promise struct {
    wg  sync.WaitGroup
    res string
    err error
}

func NewPromise(f func() (string, error)) *Promise {
    p := &Promise{}
    p.wg.Add(1)
    go func() {
        p.res, p.err = f()
        p.wg.Done()
    }()
    return p
}

func (p *Promise) Then(r func(string), e func(error)) {
    go func() {
        p.wg.Wait()
        if p.err != nil {
            e(p.err)
            return
        }
        r(p.res)
    }()
}

playground


3
投票

"From Events to Futures and Promises and back"(2016年2月出版)上有一篇名为Martin Sulzmann的论文,涵盖了你想要实现的目标。摘要说:

基于渠道通信和期货/承诺的事件是强大的,但对于并发编程而言看似不同的概念。我们表明,一个概念可以用另一个概念表达,但却没有那么费力。我们的结果提供了基于轻量级库的方法来实现事件和期货/承诺。实证结果表明,我们的方法在实践中运作良好。

根据该报纸,期货看起来像这样:

type Comp struct {
    value interface{}
    ok    bool
}

type Future chan Comp

func future(f func() (interface{}, bool)) Future {
    future := make(chan Comp)

    go func() {
        v, o := f()
        c := Comp{v, o}
        for {
            future <- c
        }
    }()

    return future
}

承诺的实施如下:

type Promise struct {
    lock chan int
    ft   Future
    full bool
}

func promise() Promise {
    return Promise{make(chan int, 1), make(chan Comp), false}
}

func (pr Promise) future() Future {
    return pr.ft
}

阅读论文了解详细信息,组合器等。


1
投票

有很多方法可以做到这一点,但我所做的例如是调整NewPromise()以将一个函数作为一个接受结果和错误通道的arg。然后NewPromise方法使用此函数初始化一个go例程,返回带有相同通道的promise。如果你调用.Then方法,这基本上需要两个函数作为参数。一个将处理您通过结果通道(字符串)的类型和一个处理错误通道的结果类型(错误)的类型。然后.Then方法调用goroutine中的私有.then()方法来选择首先发生的结果,或结果或错误,然后调用适合每个结果的函数。

例如,我只使用了一个简单的自动收报机等待一秒,然后通过结果通道发送“hi”。

我希望这能让你了解一种方法。

GoLang游乐场:https://play.golang.org/p/xc1xvv7hRx


1
投票

我也在尝试实现javascript的承诺:)。这是一个学习目的项目。在这个实现中,我学习了go的频道,选择,goroutine。我认为这个小型图书馆满足您的需求。

p := New(func(resolve func(interface{}), reject func(error)) {
    resolve("sonla")
})

p.Then(func(data interface{}) interface{} {
    fmt.Printf("What I get is %v\n", data.(string))
    return nil
})

Await(p)

欢迎贡献,如果有人有更好的想法在golang实现承诺。这是我的repo

© www.soinside.com 2019 - 2024. All rights reserved.