Is there a way to cancel execution of method in ca

2019-07-31 22:06发布

问题:

I have a problem, that I could not find any answear yet. And this is my first project with use of threading and Tasks. When my task is cancelled, it keeps executing time consuming method.

Right now I have not idea how to stop execution of the method together with the task.

Below is a loop, that runs tasks. Every single task is running a ParseHorseData method, that runs also several other methods. Execution of them takes sometimes a lot of time.

After the task is cancelled, before await Task.WhenAll(tasks); is completed, it takes a lot of time.

So, as in the question, is there a way to cancel execution of method in cancelled task?

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:

is there a way to cancel execution of method in cancelled task?

All cancellation is cooperative. The method being executed must pass the CancellationToken into the methods that it calls, and either:

  1. Periodically poll for cancellation using ThrowIfCancellationRequested. This approach is more appropriate for CPU-bound loops.
  2. Take an action on cancellation using Register. This approach is more appropriate for interfacing with non-CancellationToken-based cancellation systems.

In this case, it sounds like polling is appropriate. I strongly recommend polling via ThrowIfCancellationRequested and not IsCancellationRequested, because when a task is canceled, it should throw an OperationCanceledException when awaited. This is how the calling code knows it has been canceled.

Example:

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;
       }
    ...
  }
});