2016-03-10 6 views
5

Ich versuche, Promise in Go zu implementieren, die der in Javascript ähneln würde.Implementieren von Versprechen mit Kanälen 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. 
} 

Wie mache ich folgendes:

  1. Führen Sie einen goroutine, die Promise zum Haupt goroutine rechts weg zurück.
  2. Asynchron etwas auf der Hauptroutine tun, während für etwas warten, bis entweder Promise.Result oder Promise.Error

  3. Sobald etwas gesendet wird, kehrt aus dem goroutine und machen, dass Kanal lesen verfügbar werden gesendet werden soll.

Antwort

7

Ein anderer Ansatz ohne die Verwendung von Kanälen, die es ein bisschen schneller macht/effizienter:

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

Es gibt eine Tonne von Möglichkeiten, dies zu tun, aber was ich zum Beispiel getan wird NewPromise eingestellt() eine Funktion als arg zu nehmen, die das Ergebnis und Fehlerkanäle akzeptieren. Dann initialisiert die NewPromise-Methode eine Go-Routine mit dieser Funktion und gibt das Versprechen mit denselben Kanälen zurück, von denen gelesen werden soll. Wenn Sie die .Then-Methode aufrufen, übernimmt das im Wesentlichen zwei Funktionen als Argumente. Eine, die den Typ behandelt, den Sie durch den Ergebniskanal (Zeichenfolge) übergeben, und eine, die den Ergebnistyp des Fehlerkanals (Fehler) behandelt. Die .Then-Methode ruft dann eine private .then() -Methode in einer Goroutine auf, um auszuwählen, was zuerst passiert, entweder das Ergebnis oder der Fehler, und ruft dann die für jedes Ergebnis geeignete Funktion auf.

Für das Beispiel habe ich nur einen einfachen Ticker verwendet, der eine Sekunde wartet und dann "Hi" durch den Ergebniskanal sendet.

Ich hoffe, dies gibt Ihnen eine Idee von einer Möglichkeit, dies zu tun.

golang Spielplatz: https://play.golang.org/p/xc1xvv7hRx

2

Es gibt ein Papier "From Events to Futures and Promises and back" von Martin Sulzmann genannt (veröffentlicht im Februar 2016), die beschreibt, was Sie erreichen möchten. Die Zusammenfassung sagt:

Ereignisse auf der Grundlage der Kanal-Kommunikation und Futures/Versprechen sind mächtig, aber scheinbar unterschiedliche Konzepte für die gleichzeitige Programmierung. Wir zeigen, dass sich das eine Konzept mit erstaunlich geringem Aufwand in Bezug auf das andere ausdrücken lässt. Unsere Ergebnisse bieten leichte bibliotheksbasierte Ansätze zur Implementierung von Ereignissen und Terminen/Versprechen. Empirische Ergebnisse zeigen, dass unser Ansatz in der Praxis gut funktioniert.

Nach dem Papier, schauen Futures wie folgt aus:

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 
} 

Während Versprechen umgesetzt werden, wie folgt:

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 
} 

das Papier für Details, combinators und Lesen Sie mehr nach oben.