Keeping Promises with Feeds in Go

I am trying to implement Promise in Go, which will be similar to 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. } 

How to do the following:

  • Launch goroutine which return Promise to the main rule of goroutine far.
  • Asynchronously do something in the main procedure, expecting everything to be sent to Promise.Result or Promise.Error

  • Once something has been posted, return from goroutine and make it readable.

+5
source share
3 answers

A different approach without the use of channels, which makes it a little faster / more efficient:

 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

+7
source

There's an article called "From Events to Futures and Promises and Back" by Martin Sulzmann (published in February 2016) that talks about what you are trying to achieve. The abstract says:

Channel-based events and futures / promises are powerful, but seemingly different, concepts of parallel programming. We show that one concept can be expressed in terms of another with surprisingly little effort. Our results offer lightweight library approaches for implementing events and futures / promises. Empirical results show that our approach works well in practice.

According to the document, futures look like this:

 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 } 

While Promises are implemented as follows:

 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 } 

Read paper for parts, combinators, etc.

+2
source

There are many ways to do this, but what I did, for example, edited NewPromise (), to take a function as an argument that will take result and error channels. The NewPromise method then initializes the go procedure with this function, returning a promise with the same channels that should be read. if you call the .Then method, it basically takes two functions as arguments. One that will handle the type that you pass through the resulting channel (string), and one that processes the type of the result of the error channel (error). The .Then method then calls the private .then () method in goroutine to select which first happens, either the result or the error, and then calls the function that is appropriate for each result.

As an example, I used a simple ticker that waits one second and then sends a hello through the resulting channel.

Hope this gives you an idea of ​​one way to do this.

GoLang Playground: https://play.golang.org/p/xc1xvv7hRx

+1
source

Source: https://habr.com/ru/post/1244843/


All Articles