2016-12-29 1 views
5

Ich habe zwei asynchrone Operationen, so habe ich diese Funktionen:Wie führe ich zwei Async <> Aufrufe mit unterschiedlichen Ergebnistypen parallel aus?

// Returs Async<Person> 
let GetPerson = 
    ... 

// Returs Async<Address> 
let GetAddress = 
    ... 

Was ist der idiomatische Weg, um sie parallel auszuführen und deren Ergebnisse zu erzielen?

Mein Ausgangspunkt ist dieser Ansatz.

let MyFunc = async { 
    let! person = GetPerson() 
    let! address = GetAddress() 
    ... 
    } 

Dies funktioniert, aber das führt die beiden Operationen nacheinander.

Ich habe auch versucht, diese (basierend auf meiner C# -Erfahrung).

let MyFunc = async { 
    let personA = GetPerson() 
    let addressA = GetAddress() 
    let! person = personA 
    let! address = addressA 
    ... 
    } 

Aber es funktioniert nicht, es führt auch die zwei Operationen nacheinander.

Was die meisten der Dokumentation sagt, ist Async.Parallel mit einer Sequenz zu verwenden, aber das Problem ist, dass der Ergebnistyp der beiden Operationen unterschiedlich sind, so dass ich sie nicht in eine Sequenz einfügen kann.

let MyFunc = async { 
    let personA = GetPerson() 
    let addressA = GetAddress() 

    [personA; addressA] 
    |> Async.Parallel 
    ... 
    } 

Dies ergibt einen Übersetzungsfehler, da die beiden Werte verschiedene Typen haben. (Und mit dieser Syntax, wie könnte ich die tatsächlichen Ergebnisse erhalten?)

Was ist der idiomatische Weg, dies zu tun?

Antwort

8

Der idiomatische Ansatz ist es, beide Berechnungen beginnen Async.StartAsChild und anschließend für ihre Fertigstellung warten mit einem zweiten let!:

let MyFunc = async { 
    let! personWork = GetPerson() |> Async.StartChild 
    let! addressWork = GetAddress() |> Async.StartChild 
    let! person = personWork 
    let! address = addressWork 
    // (...) 
    } 

Gerade GetPerson Aufruf tatsächlich nicht mit der Arbeit beginnen - anders als in C#, wo Aufgaben erstellt werden gestartet , F # -Arbeitsabläufe sind nur Beschreibungen der auszuführenden Arbeiten und müssen daher explizit gestartet werden. Die Operation Async.StartChild bietet Ihnen einen Workflow, der die Arbeit startet und einen anderen Workflow zurückgibt, der verwendet werden kann, um auf seinen Abschluss zu warten.

+0

Wenn "GetPerson" und "GetAddress" ebenfalls asynchrone Primitive sind, sollten sie nach Konvention auch Async vorangestellt werden. d.h. 'asyncGetPerson 'und' asyncGetAddress '? – Chinwobble

+1

Dies ist sicherlich der Fall für F # Bibliotheksfunktionen ('AsyncGetResponse' vs.' GetResponse'). Ich würde diesem Muster folgen, wenn ich synchrone und asynchrone Versionen hätte, aber wahrscheinlich nicht, wenn ich Code schreibe, der nur asynchrone Version hat. –

+0

@TomasPetricek Ich bemerkte, dass für '' Async.Merge'' auf Ihrem Joinads-Blog '' Async.Parallel'' statt dieser 'idiomatischen' Methode verwendet wurde. Ich bin neugierig, warum Sie einen solchen Ansatz verwendet haben, ist es für ein bestimmtes Szenario effizienter? – Gustavo

Verwandte Themen