【问题标题】:How to schedule a TaskCompletionSource.Task with a TaskScheduler?如何使用 TaskScheduler 安排 TaskCompletionSource.Task?
【发布时间】:2013-02-14 22:56:39
【问题描述】:
    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);
        }
    }

在上面的示例中,taskContinuationOptions 选项是否会传播到 TaskCompletionSource.Task?在调试模式下,我可以看到 t1 和 t2 是两个不同的对象。实际上,如果将 state 传递给 StartNew(...),它只对 t1 可用,对 t2 不可用。

TaskFactory 在这种情况下仅用于将工作提交给特定的 TaskScheduler,ts。它还创建另一个任务的事实使代码令人困惑。有没有更容易混淆的方法来做到这一点?我不明白为什么 TaskCompletionSource 作为任务生产者不像 TaskFactory 那样可配置。

【问题讨论】:

  • 你从哪里得到这个代码?如果您正在创建 Task 对象,则不需要 TaskCompletionSource 对象--TCS 通常用于未使用 Task 实现的异步操作(如 APM、EAP。您正在有效地创建使用 TCS 的两个任务。
  • 如何通过Task暴露捕获的异常?我从 msdn 获得了代码:msdn.microsoft.com/en-us/library/dd449174(v=vs.100).aspx。我在代码示例中添加了 OnTaskSignaled。
  • 好的,我看到 Task 公开了相同的 API。我被msdn上的例子弄糊涂了。谢谢。
  • 是的,您可以使用Task&lt;T&gt; 做同样的事情。您可以通过 Result 周围的 try/catch 来获取异常,或者查看 Exception 属性。它们可能是AggregateException,你必须查看Flattened 中的InnerExceptions 才能获得真正的异常AggregateExcpetion msdn.microsoft.com/en-us/library/dd997415.aspx 我建议使用async/await 来更好地处理异常,如果你能够。 (VS2012)
  • "I don't understand why TaskCompletionSource being a Task producer is not as configurable as TaskFactory."TaskCompletionSourceTaskFactory可配置。您可以使用 TCS 做任何事情,您不仅限于使用 TaskFactory 的方式在构造函数中提供的一小部分选项。你可以做任何你想做的事情来确定什么是真正的“工作”,这100%取决于你。这就是TaskCompletionSourcepoint

标签: c# c#-4.0 task-parallel-library


【解决方案1】:

您没有理由使用TaskCompletionSource。如果您从 lambda 返回值,则从 StartNew() 返回的 Task 将包含您想要的内容:成功时的结果和失败时的异常。

另外,我认为TaskFactory 中的TaskContinuationOptions 仅适用于直接通过工厂启动的延续(例如使用ContinueWhenAll())。因此,我认为您根本不需要TaskFactory,但您应该分别为每个任务(原始任务和延续任务)指定选项。虽然我认为当前方法之外的人应该设置内部延续的执行方式很奇怪。

回答您的问题:安排TaskCompletionSource 和一些TaskFactory 是没有意义的,因为TaskCompletionSource 实际上并没有执行。

通过这些更改,您的代码将如下所示:

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;
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2021-08-21
  • 2023-02-02
  • 2013-07-25
  • 1970-01-01
  • 2021-08-20
  • 1970-01-01
  • 2016-01-26
  • 1970-01-01
相关资源
最近更新 更多