2016-03-10 18 views
5

Sto cercando di implementare Promise in Go che sarebbe simile a quello di Javascript.Implementazione di promessa con i canali in Go

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. 
} 

Come faccio a effettuare le seguenti operazioni:

  1. eseguire un goroutine, che restituiscono Promise al goroutine principale destra distanza.
  2. in modo asincrono fare qualcosa sulla routine principale mentre attendere nulla da inviare a uno o Promise.ResultPromise.Error

  3. Una volta che qualcosa viene inviato, torna dalle goroutine e fare che canali disponibili per essere letto.

risposta

7

Un approccio diverso senza l'utilizzo di canali, il che lo rende un po 'più veloce/più efficiente:

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

1

ci sono un sacco di modi per farlo, ma quello che ho fatto per esempio viene regolato NewPromise() per scattare una funzione come un ARG che accetterà i canali di risultato e di errore. Quindi il metodo NewPromise inizializza una routine go con questa funzione, restituendo la promessa con gli stessi canali da cui leggere. se chiami il metodo .Then, sostanzialmente prende due funzioni come argomenti. Uno che gestirà il tipo che si sta attraversando il canale dei risultati (stringa) e uno che gestisce il tipo di risultato del canale di errore (errore). Il metodo .Then quindi chiama un metodo .then() privato in una goroutine per selezionare su quale cosa accade prima, sia il risultato, sia l'errore, quindi chiama la funzione appropriata per ogni risultato.

Per l'esempio, ho usato solo un semplice ticker che aspetta un secondo e poi invia "hi" attraverso il canale dei risultati.

Spero che questo ti dia un'idea di un modo per farlo.

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

2

C'è un articolo intitolato "From Events to Futures and Promises and back" da Martin Sulzmann (pubblicato a febbraio 2016) che copre ciò che stai cercando di ottenere. L'abstract dice:

Gli eventi basati su comunicazioni di canale e future/promesse sono concetti potenti ma apparentemente diversi per la programmazione concorrente. Mostriamo che un concetto può essere espresso in termini di altro con uno sforzo sorprendentemente piccolo. I nostri risultati offrono approcci basati su librerie leggere per implementare eventi e future/promesse. I risultati empirici mostrano che il nostro approccio funziona bene nella pratica.

Secondo il giornale, i futures simile a questa:

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 
} 

Mentre le promesse sono implementate come segue:

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 
} 

Leggere il giornale per i dettagli, combinatori e altro ancora.

Problemi correlati