从任务列表中取消任务

Cancelling a task from a list of tasks

我需要轮询数据库并为每个 table 创建镶木地板文件。此任务将 运行 与要创建的线程数的一些可配置限制并行。
添加线程并且任务开始 运行 后,我需要设置一个计时器,以便如果任何查询花费的时间超过某个指定时间,则可以取消任务并关闭该线程。如果集合中还有任务,那么将调用下一个线程。
我正在使用 CancellationTokenSource 但它没有按预期工作。

public async static Task CreateExtractionAndUpload(ConfigurationDetails config)
{
    CancellationTokenSource cts = new CancellationTokenSource();
    cts.CancelAfter(10000);
    
    List<Task> getData = new List<Task>();
    foreach (var query in config.Root.Queries)
    {
        getData.Add(Task.Run(() => DoExtractionFromQueries(query, dbManager, cts.Token)));
    }

     await Task.WhenAll(getData);
}

private async static void DoExtractionFromQueries(ExtractionQueries query, DBManager dBManager, CancellationToken cancelToken)
{
    try
    {
        while (!cancelToken.IsCancellationRequested)
        {
            Thread.Sleep(20000);
            var dataTable = dBManager.GetDataTable(query.Query, System.Data.CommandType.Text);
            //ParaquetFileHandler.GenerateParquetFile(dataTable);
        }
    }
    catch (TimeoutException ex)
    {
        Logger.Error("Query taking longer than expected time!", ex);
    }
    catch (Exception ex)
    {
        Logger.Error("Exception in running query!", ex);
    }
}

我做错了什么以及如何纠正?
如何限制线程数?
我可以限制 Parallel.Foreach 中的线程,但是我可以在超时后取消任务吗?

如果您不能使 GetDataTable 异步(并接受取消令牌),实现此目的的一种方法是配置数据库连接的超时,然后您可以:

 Parallel.ForEach(
    source: config.Root.Queries,
    parallelOptions: new ParallelOptions { MaxDegreeOfParallelism = NUMBER },
    body: (query) => DoExtractionFromQueries(query, dBManager)

请注意,如果您采用推荐的方式使 GetDataTable 异步,那么您将从 并行性 移动到 并发性 。使用任务时,没有简单的方法来设置“最大并发级别”。您需要进行一两次搜索才能找到 Task.WhenAll 的替代方案,它允许设置并发任务数量的限制。

I am using CancellationTokenSource but it is not working as expected.

.NET 中的取消是合作的。所以代码必须检查是否取消。如果不检查,则不会取消。

在这种情况下,您可能需要修改 dBManager.GetDataTable 以使其具有取消感知功能:向该方法添加一个 CancellationToken 参数,并将其传递给任何 long-运行 它调用的方法。