问题
This question combines two topics I don't fully understand
Reading through a paper about async in F#, I came across the topic of Agents/MailboxProcessors, which can be used to implement reactive state machines. Could the new async/await functionality in C#5 be used to implement something similar in C#, or is there already something analogue that would be better suited?
回答1:
With a bit of pretty horrible hacking, you can use the MailboxProcessor
type from C# using async
. Some difficulties are that the type uses some F# specific features (optional arguments are options, functions are FSharpFunc
type, etc.)
Technically, the biggest difference is that F# async is dealyed while C# async creates a task that is already running. This means that to construct F# async from C#, you need to write a method that takes unt -> Task<T>
and creates Async<T>
. I wrote a blog post that discusses the difference.
Anwyay, if you want to experiment, here is some code you can use:
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();
}
As you can see, this looks really horrible :-).
In principle, it could be possible to write a C# friendly wrapper for the
MailboxProcessor
type (just extract the ugly bits from this code), but there are some problems.In F# you often use tail-recursive asyncs to implement the state machine in the mailbox processor. If you write the same thing in C#, you'll eventually get
StackOverflow
, so you'd need to write loops with mutable state.It is perfectly possible to write the agent in F# and call it from C#. This is just a matter of exposing C#-friendly interface from F# (using the
Async.StartAsTask
method).
回答2:
In principle, I expect it would be straightforward to translate these F# APIs into C#-plus-async-await.
In practice, I am unclear if it would come out beautiful, or ugly and full of extra type annotations, or simply un-idiomatic and in need of some API-massaging to make it feel more at home in C#. I think the jury is out until someone does the work and tries it. (I presume there is no such sample in the await CTP.)
回答3:
You might nave a look at Stact. It hasn't been updated in a little while, but if you wanted to make something with a little better C# support, you might find it a good starting point. I don't think it's up-to-date with async/await, though.
来源:https://stackoverflow.com/questions/4075189/agent-mailboxprocessor-in-c-sharp-using-new-async-await