Ben*_*jol 7 c# f# agent c#-to-f# async-await
这个问题结合了我不完全理解的两个主题
通过阅读有关F#中异步的文章,我遇到了Agent/MailboxProcessors的主题,它可用于实现反应状态机.是否可以使用C#5中的新异步/等待功能来实现C#中类似的功能,或者是否已经存在更适合的类似模拟?
Tom*_*cek 11
有一点非常可怕的黑客攻击,你可以使用MailboxProcessor
C#中的类型async
.一些困难是该类型使用一些F#特定功能(可选参数是选项,功能是FSharpFunc
类型等)
从技术上讲,最大的区别是F#async被分析,而C#async创建一个已经运行的任务.这意味着要从C#构造F#异步,您需要编写一个接受unt -> Task<T>
和创建的方法Async<T>
.我写了一篇讨论差异的博客文章.
Anwyay,如果您想进行实验,可以使用以下代码:
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();
}
Run Code Online (Sandbox Code Playgroud)
如你所见,这看起来非常可怕:-).
原则上,可以为该MailboxProcessor
类型编写一个C#友好包装器(只是从这段代码中提取丑陋的位),但是存在一些问题.
在F#中,您经常使用尾递归异步来实现邮箱处理器中的状态机.如果你在C#中编写相同的东西,你最终会得到StackOverflow
,所以你需要编写具有可变状态的循环.
完全可以在F#中编写代理并从C#中调用它.这仅仅是(使用从F#曝光C# -友好界面的物质Async.StartAsTask
的方法).
原则上,我希望将这些 F# API 转换为 C#-plus-async-await 会很简单。
在实践中,我不清楚它是否会变得漂亮,或者丑陋并且充满额外的类型注释,或者只是不惯用并且需要一些 API 按摩以使其在 C# 中感觉更自在。我认为在有人完成工作并尝试之前,评判是没有定论的。(我认为等待CTP中没有这样的样本。)
归档时间: |
|
查看次数: |
2580 次 |
最近记录: |