从任务列表中取消任务
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-运行 它调用的方法。
我需要轮询数据库并为每个 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-运行 它调用的方法。