有没有办法取消已取消任务中方法的执行?

时间:2019-05-17 10:11:25

标签: c# wpf task cancellation

我有一个问题,我还找不到任何鞍子。这是我第一个使用线程和任务的项目。取消任务后,它会继续执行耗时的方法。

现在我还不知道如何与任务一起停止执行该方法。

下面是运行任务的循环。每个任务都运行一个ParseHorseData方法,该方法也运行其他几种方法。执行它们有时会花费很多时间。

在取消任务之后,await Task.WhenAll(tasks);完成之前,这需要很多时间。

那么,就像在问题中一样,有没有办法取消已取消任务中方法的执行?

List<Task> tasks = new List<Task>();
int loopCounter = 0;
int taskCounter = 0;

//for all races in the file
for (int i = 0; i < _allRaces.Count; i ++)
{
    int j = i;

    if (TaskCancellation == true)
    {
        break;
    }

    Task task = Task.Run(async () =>
    {
        while (!_cancellationToken.IsCancellationRequested)
        {
            loopCounter++;

            ProgressBarTick("Requesting historic data", loopCounter, _allRaces.Count, 0);

            //if the race is from 2018
            if (_allRaces[j].RaceDate.Year == 2018)
            {
                Category = _allRaces[j].RaceCategory;
                Distance = _allRaces[j].RaceDistance.ToString();

                //for all horses in the race
                for (int h = 0; h < _allRaces[j].HorseList.Count; h++)
                {
                    HorseDataWrapper horse = new HorseDataWrapper();


                    //TIME CONSUMING
                    horse = ParseHorseData(_allRaces[j].HorseList[h], _allRaces[j].RaceDate);
                    _allRaces[j].HorseList[h] = horse;
                }
            }

            taskCounter++;

            if (loopCounter >= _allRaces.Count)
            {
                ProgressBarTick("Testing on historic data", taskCounter, _allRaces.Count, 0);
            }
        }
    }, _tokenSource.Token);

    tasks.Add(task);
}

try
{
    await Task.WhenAll(tasks);
}
catch (TaskCanceledException)
{
    //
}
finally
{
    _tokenSource.Dispose();
}

1 个答案:

答案 0 :(得分:2)

  

是否可以取消已取消任务中方法的执行?

所有取消都是合作的。正在执行的方法必须将CancellationToken传递到其调用的方法中,并且可以:

  1. 使用ThrowIfCancellationRequested定期轮询取消。这种方法更适合CPU绑定的循环。
  2. 使用Register进行取消操作。这种方法更适合与基于非CancellationToken的取消系统接口。

在这种情况下,听起来轮询是适当的。我强烈建议通过ThrowIfCancellationRequested而不是IsCancellationRequested进行轮询,因为取消任务时,应在OperationCanceledException时抛出await。这就是调用代码知道它已被取消的方式。

示例:

Task task = Task.Run(async () =>
{
  while (true)
  {
    _cancellationToken.ThrowIfCancellationRequested();
    ...
       //for all horses in the race
       for (int h = 0; h < _allRaces[j].HorseList.Count; h++)
       {
          _cancellationToken.ThrowIfCancellationRequested();
          HorseDataWrapper horse = new HorseDataWrapper();
          horse = ParseHorseData(_allRaces[j].HorseList[h], _allRaces[j].RaceDate);
          _allRaces[j].HorseList[h] = horse;
       }
    ...
  }
});