IScheduler界面提供

public static IDisposable Schedule(this IScheduler scheduler, Action action)




public static IDisposable ScheduleAsync(this IScheduler scheduler, Func<IScheduler, CancellationToken, System.Threading.Tasks.Task<IDisposable>> action)


ScheduleAsync的方法说明:

    // Summary:
    //     Schedules work using an asynchronous method, allowing for cooperative scheduling
    //     in an imperative coding style.
    //
    // Parameters:
    //   scheduler:
    //     Scheduler to schedule work on.
    //
    //   action:
    //     Asynchronous method to run the work, using Yield and Sleep operations for
    //     cooperative scheduling and injection of cancellation points.
    //
    // Returns:
    //     Disposable object that allows to cancel outstanding work on cooperative cancellation
    //     points or through the cancellation token passed to the asynchronous method.
    //
    // Exceptions:
    //   System.ArgumentNullException:
    //     scheduler or action is null.


有人可以解释这两种方法之间的区别吗?

我什么时候应该使用ScheduleAsync?

我应该何时使用Schedule?

允许以命令式编码方式进行协作调度意味着什么?

谢谢。

最佳答案

向前

该答案基于Raa团队在this帖子中直接给出的明确解释-注意这一点很长,并且涉及的内容不仅仅限于此。转到Rx查询运算符中的“利用”异步”一节,并进行全部说明,包括标题为“使调度程序更易于与” await”一起使用的部分中ScheduleAsyc上的特定示例。

这是我的解释:

摘要

ScheduleAsync的主要动机是拥抱C#5的异步/等待功能,以简化编写代码来执行许多事件的“公平”调度,否则这些事件可能导致其他操作的调度程序匮乏。这就是“协作调度”的含义-与共享调度程序的其他代码很好地协作。为此,您可以安排下一个事件,然后产生控制权,直到该事件触发并挂接到该事件以安排下一个事件,依此类推。

在Rx 2.0之前,这是通过递归调度实现的。

天真的例子

这是链接文章中的示例,提供了Range运算符的实现。此实现效果很差,因为它通过不产生控制权来使调度程序饿死:

static IObservable<int> Range(int start, int count, IScheduler scheduler)
{
    return Observable.Create<int>(observer =>
    {
        return scheduler.Schedule(() =>
        {
            for (int i = 0; i < count; i++)
            {
                Console.WriteLine("Iteration {0}", i);
                observer.OnNext(start + i);
            }
            observer.OnCompleted();
        });
    });
}


请注意,OnNext如何陷入循环中,从而在不产生控制权的情况下锤击调度程序(如果调度程序是单线程的,则尤其糟糕)。它使其他操作无法安排它们的动作,并且不允许取消操作中止。我们该如何解决呢?

递归计划-Pre-Rx 2.0解决方案

这是递归调度解决的旧方法-很难知道发生了什么。这不是“命令式编码样式”。递归调用self()在您第一次看到它时就非常不透明,在我看来,这是第十个,尽管我最终知道了。 This classic post by the legendary Bart de Smet will tell you more than you'll ever need to know about this technique。无论如何,这是递归样式:

static IObservable<int> Range(int start, int count, IScheduler scheduler)
{
    return Observable.Create<int>(observer =>
    {
        return scheduler.Schedule(0, (i, self) =>
        {
            if (i < count)
            {
                Console.WriteLine("Iteration {0}", i);
                observer.OnNext(start + i);
                self(i + 1); /* Here is the recursive call */
            }
            else
            {
                observer.OnCompleted();
            }
        });
    });
}


更公平的是,如果取消订阅,则下一个未决的计划操作将被取消。

新的异步/等待样式

这是通过异步/等待的编译器转换而延续的新方法,它允许“命令式编码样式”。请注意,与递归样式相比,动机是更大的可读性-async / await脱颖而出,通常以.NET特有的方式显示正在发生的事情:

static IObservable<int> Range(int start, int count, IScheduler scheduler)
{
    return Observable.Create<int>(observer =>
    {
        return scheduler.ScheduleAsync(async (ctrl, ct) =>
        {
            for (int i = 0; i < count; i++)
            {
                Console.WriteLine("Iteration {0}", i);
                observer.OnNext(i);
                await ctrl.Yield(); /* Use a task continuation to schedule next event */
            }
            observer.OnCompleted();

            return Disposable.Empty;
        });
    });
}


它看起来像一个for循环,但实际上await ctrl.Yield()将产生控制权,允许其他代码到达调度程序。它使用“任务”延续来一次仅调度一个事件-也就是说,每次迭代仅在前一个迭代完成后才发布到调度程序中,从而避免直接在调度程序上排长队。取消也可以,这次Rx框架将订阅的处置转换为通过ct传递的取消令牌。

如果链接仍然有效,我建议您阅读original post

关于c# - IScheduler.Schedule与IScheduler.ScheduleAsync?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19489004/

10-12 00:17