2016-03-10 23 views
5

Próbuję wdrożyć Promise in Go, która byłaby podobna do tej w JavaScript.Realizacja obietnicy z kanałami w 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. 
} 

Jak mogę wykonać następujące czynności:

  1. Uruchom goroutine, które zwracają Promise do głównego goroutine prawo dalej.
  2. asynchronicznie zrobić coś na głównej procedury podczas czekać na cokolwiek mają być wysłane do obu Promise.Result lub Promise.Error

  3. Gdy coś jest wysyłane, powrócić z goroutine i sprawiają, że kanał dostępny do odczytu.

Odpowiedz

7

Inne podejście bez korzystania z kanałów, co czyni go nieco szybciej/bardziej wydajne:

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

Istnieje wiele sposobów, aby to zrobić, ale na przykład zrobiłem regulację NewPromise(), aby przyjąć funkcję jako argument, który zaakceptuje kanały wyników i błędów. Następnie metoda NewPromise inicjuje procedurę ruty z tą funkcją, zwracając obietnicę tymi samymi kanałami, z których można odczytać. jeśli wywołasz metodę .Then, w zasadzie przyjmuje ona dwie funkcje jako argumenty. Jeden, który poradzi sobie z typem, przez który przechodzisz przez kanał wyników (ciąg) i taki, który obsługuje typ wyniku kanału błędu (błąd). Metoda .Then następnie wywołuje prywatną metodę .then() w goroutine w celu wybrania, która z nich jest pierwsza, albo wynik, albo błąd, a następnie wywołuje funkcję odpowiednią dla każdego wyniku.

Dla przykładu, użyłem tylko prostego paska, który czeka jedną sekundę, a następnie wysyła "cześć" przez kanał wyników.

Mam nadzieję, że daje to wyobrażenie o jednym sposobie na zrobienie tego.

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

2

Jest papier zwany "From Events to Futures and Promises and back" przez Martin Sulzmann (opublikowane w lutym 2016 r.), które obejmuje to, co próbujesz osiągnąć. Streszczenie mówi:

Wydarzenia oparte na komunikacji kanału i przyszłości/obietnicach są potężnymi, ale pozornie różnymi koncepcjami programowania współbieżnego. Pokazujemy, że jedno pojęcie można wyrazić w kategoriach drugiego z zaskakująco małym wysiłkiem. Nasze wyniki oferują lekkie, oparte na bibliotekach podejścia do realizacji wydarzeń i przyszłości/obietnic. Wyniki empiryczne pokazują, że nasze podejście sprawdza się dobrze w praktyce.

Według gazety, futures wyglądać następująco:

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 
} 

Podczas gdy obietnice są realizowane w następujący sposób:

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 
} 

Czytaj gazetę Szczegółowe kombinatorów i więcej.

Powiązane problemy