如何确定某项任务是否已经等待/检查过结果?
我创建并激活了List
个Task
个后台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}}
答案 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()
,无论是否等待。