2016-12-07 7 views
4

Я довольно новичок в программировании на основе задач и пытаюсь определить, как вернуть задачу и убедиться, что она была запущена. Код, который я получил, не был тем, чего я ожидал. Консольное приложение выглядит следующим образом:Какая задача возвращается и почему это состояние задачи RanToCompletion

public static void Main(string[] args) 
    { 
     var mySimple = new Simple(); 
     var cts = new CancellationTokenSource(); 
     var task = mySimple.RunSomethingAsync(cts.Token); 
     while (task.Status != TaskStatus.RanToCompletion) 
     { 
      Console.WriteLine("Starting..."); 
      Thread.Sleep(100); 
     } 

     Console.WriteLine("It is started"); 
     Console.ReadKey(); 
     cts.Cancel(); 
    } 

public class Simple 
{ 
    public async void RunSomething(CancellationToken token) 
    { 
     var count = 0; 
     while (true) 
     { 
      if (token.IsCancellationRequested) 
      { 
       break; 
      } 
      Console.WriteLine(count++); 
      await Task.Delay(TimeSpan.FromMilliseconds(1000), token).ContinueWith(task => { }); 
     } 
    } 

    public Task RunSomethingAsync(CancellationToken token) 
    { 
     return Task.Run(() => this.RunSomething(token)); 
    } 
} 

Выход:

Starting... 
0 
It is started 
1 
2 
3 
4 

Почему задача, которая возвращается имеют статус TaskStatus.RanToCompletion по сравнению с TaskStatus.Running, как мы видим, что while цикл все еще выполняется? Я проверяю статус задачи по включению задачи RunSomething в threadpool, а не в задачу RunSomething?

ответ

3

RunSomething метод async void, то есть он не предоставляет никаких средств для вызова, когда-либо определяющего, когда он заканчивается, они могут только начать операцию, а затем не имеют представления о том, что произойдет дальше. Затем вы завершаете вызов в пределах Task.Run, это планирование потока потока нити до началоRunSomething. Затем он будет завершен, как только он закончит , начиная, что Task.

Если RunSomething фактически вернулся Task, то вызывающий абонент сможет определить, когда он на самом деле закончена, и если вы не ждали от него было бы на самом деле показывают, что это было сделано до тех пор, что асинхронная работа не была на самом деле завершается (там будет не стоит использовать Task.Run, чтобы запустить его в другом аэде, вам было бы лучше просто называть его напрямую и не тратить силы на то, чтобы переместить его в поток потока потока).

1
  1. Никогда не используйте асинхронную пустоту (https://msdn.microsoft.com/en-us/magazine/jj991977.aspx) вместо этого вы должны использовать асинхронный Task

  2. Если вам нужно вызвать метод асинхронного из не-асинхронном (например, от статической силы основного) вы должны что-то вроде этого:

    mySimple.RunSomethingAsync(cts.Token).GetAwaiter().GetResult(); 
    

    Это эффективно сделает метод синхронным вызовом.