2010-11-02 5 views
7

Diese Frage zwei Themen kombiniert ich nicht vollAgent/MailboxProcessor in C# mit neuen Asynchron/erwarten

verstehen Sie einen paper Beim Lesen über async in F #, stieß ich auf das Thema Agents/MailboxProcessors, die kann verwendet werden, um reaktive Zustandsmaschinen zu implementieren. Könnte die neue async/wait Funktionalität in C# 5 verwendet werden, um etwas Ähnliches in C# zu implementieren, oder gibt es schon etwas Analoges, das besser geeignet wäre?

+0

Können Sie den defekten Link reparieren? – czifro

+0

@czifro, ok fertig. – Benjol

Antwort

3

Im Prinzip erwarte ich, dass es einfach wäre, diese F # APIs in C# -plus-async-await zu übersetzen.

In der Praxis bin ich unklar, ob es schön, oder hässlich und voll von zusätzlichen Typ Anmerkungen, oder einfach un-idiomatisch und in der Notwendigkeit von API-massaging herauskommen würde, damit es sich in C# mehr zuhause fühlt. Ich denke, die Jury ist aus, bis jemand die Arbeit macht und es versucht. (Ich nehme an, es gibt keine solche Probe in der Wartezeit CTP.)

+2

Das CTP heruntergeladen. Jetzt werde ich fortfahren, um meine Ignoranz zu erweitern, indem ich versuche :) – Benjol

+0

Ich sehe Ihre Super Breakaway machte es in die Proben, herzlichen Glückwunsch :) – Benjol

+1

Autsch! Zu schwer für mich dieses Zeug :( – Benjol

11

Mit ein bisschen ziemlich schrecklichen Hacking, können Sie die MailboxProcessor Art von C# mit async verwenden. Einige Schwierigkeiten sind, dass der Typ einige F # spezifische Funktionen verwendet (optionale Argumente sind Optionen, Funktionen sind FSharpFunc Typ, usw.)

Technisch gesehen ist der größte Unterschied, dass F # Async dealyed wird, während C# Async eine Aufgabe erstellt, die bereits ausgeführt wird . Das bedeutet, dass Sie zum Erstellen von F # -Assync aus C# eine Methode schreiben müssen, die unt -> Task<T> verwendet und Async<T> erstellt. Ich schrieb eine blog post that discusses the difference.

Anwyay, wenn Sie experimentieren wollen, hier einige Code, den Sie verwenden können:

static FSharpAsync<T> CreateAsync<T>(Func<Task<T>> f) 
{ 
    return FSharpAsync.FromContinuations<T>(
    FuncConvert.ToFSharpFunc< 
     Tuple< FSharpFunc<T, Unit>, 
      FSharpFunc<Exception, Unit>, 
      FSharpFunc<OperationCanceledException, Unit> >>(conts => { 
    f().ContinueWith(task => { 
     try { conts.Item1.Invoke(task.Result); } 
     catch (Exception e) { conts.Item2.Invoke(e); } 
    }); 
    })); 
} 

static void MailboxProcessor() { 
    var body = FuncConvert.ToFSharpFunc< 
       FSharpMailboxProcessor<int>, 
       FSharpAsync<Unit>>(mbox => 
    CreateAsync<Unit>(async() => { 
     while (true) { 
     var msg = await FSharpAsync.StartAsTask 
      (mbox.Receive(FSharpOption<int>.None), 
      FSharpOption<TaskCreationOptions>.None, 
      FSharpOption<CancellationToken>.None); 
     Console.WriteLine(msg); 
     } 
     return null; 
    })); 
    var agent = FSharpMailboxProcessor<int>.Start(body, 
       FSharpOption<CancellationToken>.None); 
    agent.Post(1); 
    agent.Post(2); 
    agent.Post(3); 
    Console.ReadLine(); 
} 

Wie Sie sehen können, das sieht wirklich schrecklich :-).

  • Im Prinzip könnte es möglich sein, einen C# freundlichen Wrapper für die MailboxProcessor Art zu schreiben (extrahiert nur die hässlichen Bits aus diesem Code), aber es gibt einige Probleme.

  • In F # verwenden Sie häufig tail-rekursive asyncs, um den Zustandsautomaten im Mailbox-Prozessor zu implementieren. Wenn Sie dasselbe in C# schreiben, erhalten Sie schließlich StackOverflow, also müssten Sie Schleifen mit veränderbarem Status schreiben.

  • Es ist durchaus möglich, den Agenten in F # zu schreiben und von C# aus aufzurufen. Dies ist nur eine Frage des Freigebens einer C# -freundlichen Schnittstelle von F # (unter Verwendung der Async.StartAsTask-Methode).

+0

Autsch, meine Augen :) Die Aufgabe -> Async 'war genau das Bit, auf dem ich stecken geblieben bin, also werde ich mir das ansehen.Wie wäre es, wenn Sie einen MailboxProcessor in C# umschreiben würden, oder wäre es aufgrund Ihres zweiten Aufzählungszeichens zur Rekursion einfach nicht die Mühe wert? – Benjol

+0

@Benjol - Ich schrieb einen ähnlichen Typ in C#. Es waren etwa 300 Zeilen Code. Der Unterschied ist eine vereinfachte API. – ChaosPandion

+0

@Benjol: Ich denke, dass das Umschreiben von MailboxProcessor in C# auch eine Option wäre. Es ist nicht einfach, das Sperren und Synchronisieren richtig zu machen (besonders für die 'TryScan'-Methode), aber ich denke, es sollte funktionieren (Sie können die Rekursion immer vermeiden, aber im Falle von _state machines_ sieht der Code ziemlich schlecht aus, also ist es schade das ist, was Benutzer schreiben müssen) –

0

Sie könnten einen Blick auf Stact werfen. Es wurde nicht in kurzer Zeit aktualisiert, aber wenn Sie etwas mit etwas besserer C# Unterstützung machen wollten, könnten Sie einen guten Ausgangspunkt dafür finden. Ich denke jedoch nicht, dass es mit async auf dem neuesten Stand ist.

Verwandte Themen