任务被取消,但不清楚原因和方式
Tasks are getting cancelled, but it's not clear why and how
我正在 运行 在 ASP.NET 框架上开发一个大型单体 Web 应用程序并添加了一个功能。我构建了一些抽象,以便 运行 并行执行多个任务。
public interface IImporter
{
Action[] GetProcessActions();
}
public class ImportTaskFactory : IDisposable
{
private readonly Task[] _tasks;
/// <summary>
/// Immediately starts all the Process tasks
/// </summary>
public ImportTaskFactory(CancellationToken cancellationToken, Action<Task> onTaskFaultedAction, IEnumerable<IImporter> importers)
{
_tasks = importers
.SelectMany(importer =>
importer
.GetProcessActions()
.Select(action =>
Task.Factory.StartNew(action, cancellationToken)
.ContinueWith(onTaskFaultedAction, TaskContinuationOptions.OnlyOnFaulted)))
.ToArray();
}
public void WaitAll(CancellationToken cancellationToken)
{
Task.WaitAll(_tasks, cancellationToken);
}
public void Dispose()
{
foreach (var task in _tasks)
{
task?.Dispose();
}
}
}
它被称为
//...
var importers = new IImporter[]
{
//...three classes deriving from IImporter
}
using (var importTasks =
new ImportTaskFactory(_cancellationTokenSource.Token, OnTaskFaulted, importers))
{
importTasks.WaitAll(_cancellationTokenSource.Token);
}
//... where:
private void OnTaskFaulted(Task task)
{
Log.Logline(task.Exception.ToString());
_cancellationTokenSource.Cancel();
}
//...
然而,当 运行 任务开始时很好并完成它们的工作,但似乎由于不明原因而停止,每个任务都抛出一个 System.Threading.Tasks.TaskCanceledException
(没有内部异常)。
如果我查看传递的 CancellationToken
,未请求取消。
几个小时以来我一直在尝试对此进行调试,但不知道发生了什么。如何以这种方式取消任务?我该如何调试呢?我的意思是我怎样才能看到是什么触发了取消?
我在 OnTaskFaulted
方法中设置了断点,但它似乎从未被调用...那是唯一调用 _cancellationTokenSource.Cancel();
的点。
这不是您问题的答案。它只是展示了如何做你想做的事,而不会出现这些讨厌的取消异常:
void ImportTaskFactory(CancellationToken cancellationToken,
Action<Task> onTaskFaultedAction, IEnumerable<IImporter> importers)
{
_tasks = importers
.SelectMany(importer => importer
.GetProcessActions()
.Select(action => Task.Run(() =>
{
try
{
action();
}
catch (Exception ex)
{
onTaskFaultedAction(Task.FromException(ex));
}
}, cancellationToken))).ToArray();
}
我将 Task.Factory.StartNew
替换为 Task.Run
, because the former requires,以便在您每次使用它时显式传递 scheduler
。
如果 onTaskFaultedAction
参数的类型是 Action<Exception>
而不是 Action<Task>
.
可能会更简单
我正在 运行 在 ASP.NET 框架上开发一个大型单体 Web 应用程序并添加了一个功能。我构建了一些抽象,以便 运行 并行执行多个任务。
public interface IImporter
{
Action[] GetProcessActions();
}
public class ImportTaskFactory : IDisposable
{
private readonly Task[] _tasks;
/// <summary>
/// Immediately starts all the Process tasks
/// </summary>
public ImportTaskFactory(CancellationToken cancellationToken, Action<Task> onTaskFaultedAction, IEnumerable<IImporter> importers)
{
_tasks = importers
.SelectMany(importer =>
importer
.GetProcessActions()
.Select(action =>
Task.Factory.StartNew(action, cancellationToken)
.ContinueWith(onTaskFaultedAction, TaskContinuationOptions.OnlyOnFaulted)))
.ToArray();
}
public void WaitAll(CancellationToken cancellationToken)
{
Task.WaitAll(_tasks, cancellationToken);
}
public void Dispose()
{
foreach (var task in _tasks)
{
task?.Dispose();
}
}
}
它被称为
//...
var importers = new IImporter[]
{
//...three classes deriving from IImporter
}
using (var importTasks =
new ImportTaskFactory(_cancellationTokenSource.Token, OnTaskFaulted, importers))
{
importTasks.WaitAll(_cancellationTokenSource.Token);
}
//... where:
private void OnTaskFaulted(Task task)
{
Log.Logline(task.Exception.ToString());
_cancellationTokenSource.Cancel();
}
//...
然而,当 运行 任务开始时很好并完成它们的工作,但似乎由于不明原因而停止,每个任务都抛出一个 System.Threading.Tasks.TaskCanceledException
(没有内部异常)。
如果我查看传递的 CancellationToken
,未请求取消。
几个小时以来我一直在尝试对此进行调试,但不知道发生了什么。如何以这种方式取消任务?我该如何调试呢?我的意思是我怎样才能看到是什么触发了取消?
我在 OnTaskFaulted
方法中设置了断点,但它似乎从未被调用...那是唯一调用 _cancellationTokenSource.Cancel();
的点。
这不是您问题的答案。它只是展示了如何做你想做的事,而不会出现这些讨厌的取消异常:
void ImportTaskFactory(CancellationToken cancellationToken,
Action<Task> onTaskFaultedAction, IEnumerable<IImporter> importers)
{
_tasks = importers
.SelectMany(importer => importer
.GetProcessActions()
.Select(action => Task.Run(() =>
{
try
{
action();
}
catch (Exception ex)
{
onTaskFaultedAction(Task.FromException(ex));
}
}, cancellationToken))).ToArray();
}
我将 Task.Factory.StartNew
替换为 Task.Run
, because the former requires,以便在您每次使用它时显式传递 scheduler
。
如果 onTaskFaultedAction
参数的类型是 Action<Exception>
而不是 Action<Task>
.