我遇到需要使用自定义调度程序来运行任务(这些需要是任务)而调度程序没有设置同步上下文的情况(因此没有ObserveOn
,SubscribeOn
,{ {1}}等我收集)。以下是我最终如何做到这一点。现在,我想知道,我不确定这是否是进行异步调用和等待结果的最合适方式。这是正确的还是有更强大或惯用的方式?
SynchronizationContextScheduler
如果不需要等待怎么办?
< edit:我找到了一个具体的,以及我正在做的here的简化示例。基本上我在奥尔良使用Rx,上面的代码是我要做的事情的简单说明。虽然我也对这种情况感兴趣。
最终代码
事实证明,在奥尔良的背景下,这有点棘手。我不知道如何使用var orleansScheduler = TaskScheduler.Current;
var someObservable = ...;
someObservable.Subscribe(i =>
{
Task.Factory.StartNew(async () =>
{
return await AsynchronousOperation(i);
}, CancellationToken.None, TaskCreationOptions.None, orleansScheduler);
});
,这将是我想要使用的东西。问题是通过使用它,ObserveOn
永远不会被调用。代码:
Subscribe
此外,指向Codeplex Orleans forums的相关主题的链接。
答案 0 :(得分:4)
对于任何现代代码,我强烈建议不要使用StartNew
。它确实有一个用例,但它非常罕见。
如果您必须使用自定义任务计划程序,建议您使用ObserveOn
TaskPoolScheduler
,并使用TaskFactory
包装程序围绕您的计划程序构建var factory = new TaskFactory(customScheduler);
var rxScheduler = new TaskPoolScheduler(factory);
someObservable.ObserveOn(rxScheduler)...
。这是一个满口的,所以这是一般的想法:
SelectMany
然后,您可以使用async void
为源流中的每个事件启动异步操作。
另一种不太理想的解决方案是使用ActionBlock
进行订阅"事件"。这是可以接受的,但你必须注意你的错误处理。作为一般规则,不允许异常传播出异步void方法。
还有第三种方法,可以将observable挂钩到TPL Dataflow块中。像{{1}}这样的块可以指定其任务调度程序,Dataflow自然可以理解异步处理程序。请注意,默认情况下,Dataflow块会一次将处理限制为单个元素。
答案 1 :(得分:3)
一般来说,不是订阅执行,而是将任务参数投影到任务执行中并且只为结果订阅更好/更惯用。这样你就可以在下游进一步组建Rx。
e.g。给出一个随机任务,如:
static async Task<int> DoubleAsync(int i, Random random)
{
Console.WriteLine("Started");
await Task.Delay(TimeSpan.FromSeconds(random.Next(10) + 1));
return i * 2;
}
然后你可能会这样做:
void Main()
{
var random = new Random();
// stream of task parameters
var source = Observable.Range(1, 5);
// project the task parameters into the task execution, collect and flatten results
source.SelectMany(i => DoubleAsync(i, random))
// subscribe just for results, which turn up as they are done
// gives you flexibility to continue the rx chain here
.Subscribe(result => Console.WriteLine(result),
() => Console.WriteLine("All done."));
}