简体   繁体   English

如何使用TaskScheduler安排TaskCompletionSource.Task?

[英]How to schedule a TaskCompletionSource.Task with a TaskScheduler?

    public Task<bool> Submit(TaskScheduler ts, Func<bool> work, object state, TaskContinuationOptions taskContinuationOptions)
    {
        TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(state, TaskCreationOptions.None);

        Task t1 = new TaskFactory(_cts.Token, TaskCreationOptions.None, taskContinuationOptions, ts).StartNew(() =>
        {
            try
            {
                tcs.SetResult(work());
            }
            catch(Exception e)
            {
                tcs.SetException(e);
            }               
        });

        Task<bool> t2 = tcs.Task;
        t2.ContinueWith(OnTaskSignaled);
        return t2;
    }

    public void OnTaskSignaled(Task<bool> signaledTask) 
    {            
        BusinessItem item = (BusinessItem)signaledTask.AsyncState;
        if (signaledTask.IsCanceled)
        {
            Console.WriteLine("{0} cancelled: Invalid State", item.Id);
        }
        else if (signaledTask.IsFaulted)
        {
            Console.WriteLine("{0} threw: {1}", item.Id, signaledTask.Exception);
        }
        else if (signaledTask.Result == true)
        {
            Console.WriteLine("{0} Succeeded", item.Id);
            // continue to submit
        }
        else if (signaledTask.Result == false)
        {
            Console.WriteLine("{0} Incomplete, retry", item.Id);
            Submit(_ts2, item.Work, item);
        }
    }

In the above example, does the taskContinuationOptions option propagate to TaskCompletionSource.Task? 在上面的示例中,taskContinuationOptions选项是否传播到TaskCompletionSource.Task? In debug mode, I can see that t1 and t2 are two different objects. 在调试模式下,我可以看到t1和t2是两个不同的对象。 In fact, if state is passed to StartNew(...), it is only available to t1, but not t2. 实际上,如果状态传递给StartNew(...),它只能用于t1,但不能用于t2。

TaskFactory in this case is used only to submit work to a specific TaskScheduler, ts. 在这种情况下,TaskFactory仅用于将工作提交给特定的TaskScheduler,ts。 The fact that it also creates another task makes the code confusing. 它还创建了另一个任务的事实使代码混乱。 Is there a less confusing way to do this? 是否有一种不那么混乱的方式来做到这一点? I don't understand why TaskCompletionSource being a Task producer is not as configurable as TaskFactory. 我不明白为什么作为Task生成器的TaskCompletionSource不像TaskFactory那样可配置。

There is no reason for you to use TaskCompletionSource . 您没有理由使用TaskCompletionSource If you return the value from the lambda, the Task returned from StartNew() will contain exactly what you want: the result on success and the exception on failure. 如果从lambda返回值,则从StartNew()返回的Task将包含您想要的内容:成功的结果和失败的异常。

Also, I think the TaskContinuationOptions in TaskFactory work only for continuations that are started directly through the factory (eg using ContinueWhenAll() ). 此外,我认为TaskFactoryTaskContinuationOptions仅适用于直接通过工厂启动的延续(例如,使用ContinueWhenAll() )。 Because of that, I think you don't need the TaskFactory at all, but you should specify the options to each task (the original and the continuation) separately. 因此,我认为您根本不需要TaskFactory ,但是您应该分别为每个任务(原始和继续)指定选项。 Though I think it's weird that someone outside of the current method should set how the internal continuation should execute. 虽然我认为当前方法之外的人应该设置内部延续应该如何执行,这很奇怪。

And to answer your question: it doesn't make sense to schedule TaskCompletionSource with some TaskFactory , because TaskCompletionSource doesn't actually execute. 并回答你的问题:使用一些TaskFactory调度TaskCompletionSource是没有意义的,因为TaskCompletionSource实际上并没有执行。

With these changes, your code will look like this: 通过这些更改,您的代码将如下所示:

public Task<bool> Submit(
    TaskScheduler ts, Func<bool> work, object state,
    TaskContinuationOptions taskContinuationOptions)
{
    var task = Task.Factory.StartNew(_ => work(), state, _cts.Token);

    task.ContinueWith(OnTaskSignaled, _cts.Token, taskContinuationOptions,
                      TaskScheduler.Default);

    return task;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM