确定是否已等待任务

时间:2013-05-08 09:46:53

标签: c# .net async-await

如何确定某项任务是否已经等待/检查过结果?

我创建并激活了ListTask个后台await,但由于异常行为,可能不会等待。在我的'finally'块中,我需要遍历此列表并Task那些尚未等待的任务,以防止它们在GC进行时引发潜在异常。

修改

我的解决方案:

首先,感谢Steve清除了我对.NET 4.5中如何处理未观察到的异常的过时理解。这很有趣。但是,我仍然对从调用方法中引发这些异常感兴趣,所以我提出了以下简单的帮助器类来提供对/// <summary> /// Collection of unobserved tasks. /// </summary> public class TaskCollection { /// <summary> /// The tasks. /// </summary> private readonly List<Task> tasks = new List<Task>(); /// <summary> /// Gets a value indicating whether this instance is empty. /// </summary> /// <value> /// <c>true</c> if this instance is empty; otherwise, <c>false</c>. /// </value> public bool IsEmpty { get { return this.tasks.Count == 0; } } /// <summary> /// Adds the specified task. /// </summary> /// <param name="task">The task.</param> /// <returns>The <see cref="task"/>.</returns> public Task Add(Task task) { Contract.Requires(task != null); Contract.Requires(!this.Contains(task)); Contract.Ensures(this.Contains(task)); Contract.Ensures(Contract.Result<Task>() == task); this.tasks.Add(task); return task; } /// <summary> /// Adds the specified task. /// </summary> /// <typeparam name="T">Task return type.</typeparam> /// <param name="task">The task.</param> /// <returns>The <see cref="task"/>.</returns> public Task<T> Add<T>(Task<T> task) { Contract.Requires(task != null); Contract.Requires(!this.Contains(task)); Contract.Ensures(this.Contains(task)); Contract.Ensures(Contract.Result<Task<T>>() == task); this.tasks.Add(task); return task; } /// <summary> /// Determines whether [contains] [the specified task]. /// </summary> /// <param name="task">The task.</param> /// <returns> /// <c>true</c> if [contains] [the specified task]; otherwise, <c>false</c>. /// </returns> public bool Contains(Task task) { Contract.Requires(task != null); return this.tasks.Contains(task); } /// <summary> /// Observes the specified task. /// </summary> /// <param name="task">The task.</param> /// <returns> /// The task. /// </returns> public Task When(Task task) { Contract.Requires(task != null); Contract.Requires(this.Contains(task)); Contract.Ensures(!this.Contains(task)); this.tasks.Remove(task); return task; } /// <summary> /// Observes the specified task. /// </summary> /// <typeparam name="T">Return type.</typeparam> /// <param name="task">The task.</param> /// <returns> /// The task. /// </returns> public Task<T> When<T>(Task<T> task) { Contract.Requires(task != null); Contract.Requires(this.Contains(task)); Contract.Ensures(!this.Contains(task)); this.tasks.Remove(task); return task; } /// <summary> /// Observes all tasks. /// </summary> /// <returns>The task.</returns> public Task WhenAll() { Contract.Ensures(this.IsEmpty); if (this.IsEmpty) { return TaskEx.FromResult<object>(null); } var taskArray = this.tasks.ToArray(); this.tasks.Clear(); return TaskEx.WhenAll(taskArray); } } 的简单管理,这些类没有被立即观察到:

Exception exception;
var tasks = new TaskCollection();
try
{
    var backgroundTask = tasks.Add(DoSomethingAsync());
    // Do something in parallel.
    await tasks.When(backgroundTask);
}
catch (Exception ex)
{
    if (tasks.IsEmpty)
    {
        throw;
    }

    exception = ex;
}

try
{
    await tasks.WhenAll();
}
catch (Exception ex)
{
    exception = new AggregateException(ex, exception);
}

throw new AggregateException(exception);

使用示例:

{{1}}

2 个答案:

答案 0 :(得分:4)

  

在我的'finally'块中,我需要遍历此列表并等待那些尚未等待的任务,以防止它们在GC进行时引发潜在异常。

不,你没有。

在.NET 4.5中,unobserved task exceptions are no longer raised during finalization

答案 1 :(得分:2)

你需要在这里小心......一旦事情开始生病,就很难保证这项任务能够完成(任何方式)。但是 - 你可以添加一个方法,如:

public static void IgnoreFailure(this Task task) {
    if (task.IsCompleted) { // observe now
        // this is just an opaque method to ensure it gets evaluated
        if (task.IsFaulted) GC.KeepAlive(task.Exception);
    }
    else { // observe in the future
        task.ContinueWith(t => {
            if (t.IsFaulted) GC.KeepAlive(t.Exception);
        }, TaskContinuationOptions.ExecuteSynchronously);
    }
}

只需在每项任务上调用t.IgnoreFailure(),无论是否等待。