我正在开发一个运行在ASP上的大型整体式web应用程序.NET框架,并添加了一个功能.为了并行运行多个任务,我构建了一些抽象.

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分(内部没有例外).

enter image description here

我已经试着调试了几个小时,但不知道发生了什么.这些任务怎么会被取消呢?我如何调试这个?我是说,我怎么知道是什么触发了取消?

我在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,因为以前的requires每次使用时都会显式地传递scheduler.

如果onTaskFaultedAction参数的类型是Action<Exception>而不是Action<Task>,可能会更简单.

Csharp相关问答推荐

CsWin32如何创建PWSTR的实例,例如GetWindowText

获取ASP.NET核心身份认证cookie名称

在命名管道上使用GRPC ASP.NET核心时如何配置命名管道权限

Take()方法如何与IAsyncEnumerable一起使用

在.NET核心项目中创建Startup.cs比在Program.cs中注册服务好吗?

如何在毛伊岛应用程序中完美地同步视图模型和视图的加载?

net中从位图获取坐标和绘制折线

如何将DotNet Watch与发布配置和传递给应用程序的参数一起使用?

将类移动到新命名空间后更新RavenDB Raven-Clr-Type

我可以查看我们向应用程序洞察发送了多少数据吗?

如何从Entity Framework Core中填充ListIInterface

如何正确处置所有动态控件?

如何使用实体框架核心对字符串_agg使用强制转换为varchar(Max)

Foreach非常慢的C#

SharpZipLib在文件名前加上目录名,生成tar.gz

如何在Cake脚本中设置MSBuild.exe的绝对路径

游戏对象走向不同的方向

C#:我需要根据换行符拆分字符串,而不是在字符串中用双引号分隔换行符

方法加载时出现类型加载异常

System.Net.Http.HttpClient返回错误&Quot;Err:缺少UA30&Quot;