这个问题结合了两个主题,我不完全理解代理/ MailboxProcessor在C#中使用新的异步/等待
通过paper约异步F#中阅读,我碰到代理/ MailboxProcessors的话题来了这可以用来实现反应状态机。 C#5中的新异步/等待功能可以用于在C#中实现类似的东西吗,还是已经有一些更适合的模拟类?
这个问题结合了两个主题,我不完全理解代理/ MailboxProcessor在C#中使用新的异步/等待
通过paper约异步F#中阅读,我碰到代理/ MailboxProcessors的话题来了这可以用来实现反应状态机。 C#5中的新异步/等待功能可以用于在C#中实现类似的东西吗,还是已经有一些更适合的模拟类?
原则上,我希望将这些F#API转换为C#-plus-async-await会很简单。
实际上,我不清楚它是否会出现漂亮,丑陋和充满额外类型的注释,或者仅仅是非惯用的,并且需要一些API-按摩使它在C#中感觉更像家一样。我认为陪审团一直到有人做这项工作并尝试。 (我认为在等待的CTP中没有这样的样本。)
由于一些非常可怕的黑客攻击,您可以使用来自C#的MailboxProcessor
类型,使用async
。一些困难是该类型使用了一些F#特有的功能(可选参数是选项,函数是FSharpFunc
类型等)
从技术上讲,最大的区别是F#异步是dealyed而C#异步创建一个已经运行的任务。这意味着要从C#构建F#异步,您需要编写一个方法,该方法需要unt -> Task<T>
并创建Async<T>
。我写了一个blog post that discusses the difference。
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();
}
正如你所看到的,这看起来很可怕:-)。
原则上,它可能是可以写入的MailboxProcessor
类型C#友好包装(只是提取此代码丑陋位),但也存在一些问题。
在F#中,您经常使用尾递归异步实现邮箱处理器中的状态机。如果你用C#编写相同的东西,你最终会得到StackOverflow
,所以你需要编写可变状态的循环。
完全可以在F#中编写代理并从C#调用它。这只是将来自F#的C#友好接口公开(使用Async.StartAsTask
方法)。
哎唷,我的眼睛:)'任务 - >异步
@ Benjol - 我在C#中写了一个类似的类型。它大约有300行代码。区别在于简化的API。 – ChaosPandion 2010-11-02 13:56:54
@ Benjol:我认为用C#重写MailboxProcessor也是一个选择。要获得锁定和同步的权利并不容易(特别是'TryScan'方法),但我认为它应该可以工作(您总是可以避免递归,但是在_state machines_的情况下代码看起来相当糟糕,所以很不幸,如果这是用户必须写的) – 2010-11-02 13:57:54
您可能会看看Stact。它有一段时间没有更新,但如果你想用更好的C#支持做一些事情,你可能会发现它是一个很好的起点。不过,我认为它不是最新的async/await。
你能解决断链吗? – czifro 2017-07-08 02:01:37
@czifro,好的。 – Benjol 2017-07-10 04:50:03