Асинхронный всегда WaitingForActivation

Я пытаюсь выяснить, что async & await ключевые слова Все о, однако выход не то, что я ожидаю.

консольное приложение выглядит следующим образом:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Foo called");
        var result = Foo(5);

        while (result.Status != TaskStatus.RanToCompletion)
        {
            Console.WriteLine("Thread ID: {0}, Status: {1}", Thread.CurrentThread.ManagedThreadId, result.Status);
            Task.Delay(100).Wait();
        }

        Console.WriteLine("Result: {0}", result.Result);
        Console.WriteLine("Finished.");
        Console.ReadKey(true);
    }

    private static async Task<string> Foo(int seconds)
    {
        return await Task.Run(() =>
            {
                for (int i = 0; i < seconds; i++)
                {
                    Console.WriteLine("Thread ID: {0}, second {1}.", Thread.CurrentThread.ManagedThreadId, i);
                    Task.Delay(TimeSpan.FromSeconds(1)).Wait();
                }

                return "Foo Completed.";
            });
    }
}

выход:

Foo called
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 0.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 1.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 2.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 3.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 4.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Result: Foo Completed.
Finished..

Я ожидал увидеть изменение статуса от WaitingForActivation после запуска метода.

как он может оставаться в этом состоянии и быть активным?

4 ответов


для моего ответа стоит помнить, что TPL (Задача-Параллельная Библиотека), Task класс а было введено до ключевых слов async-await, а ключевые слова async-await не были первоначальной мотивацией TPL.

в контексте методов, помеченных как async, в результате Task - Это не Task представляющий выполнение метода, но a Task для продолжения метода.

это только в состоянии использовать несколько возможных состояний:

  • отменено
  • неисправность
  • RanToCompletion
  • WaitingForActivation

я понимаю, что Runningможет быть лучше по умолчанию, чем WaitingForActivation, однако это может ввести в заблуждение, так как в большинстве случаев асинхронный метод выполнена фактически не работает (т. е. это может быть await - ing что-то еще). Другой вариант возможно, нужно было добавить новое значение в TaskStatus, однако это могло быть разрушительным изменением для существующих приложений и библиотек.

все это очень отличается от использования Task.Run который является частью исходного TPL, это может использовать все возможные значения TaskStatus перечисление.

если вы хотите отслеживать состояние асинхронного метода, взгляните на IProgress(T) интерфейс, это позволит вам сообщите о достигнутом прогрессе. Это сообщение в блоге,Async в 4.5: включение прогресса и отмены в асинхронных API предоставит дополнительную информацию об использовании IProgress(T) интерфейс.


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

var task = Task.Run(() =>
        {
            for (int i = 10; i < 432543543; i++)
            {
                // just for a long job
                double d3 = Math.Sqrt((Math.Pow(i, 5) - Math.Pow(i, 2)) / Math.Sin(i * 8));
            }
           return "Foo Completed.";

        });

        while (task.Status != TaskStatus.RanToCompletion)
        {
            Console.WriteLine("Thread ID: {0}, Status: {1}", Thread.CurrentThread.ManagedThreadId,task.Status);

        }

        Console.WriteLine("Result: {0}", task.Result);
        Console.WriteLine("Finished.");
        Console.ReadKey(true);

на output:

enter image description here

рассмотрим это для лучшего объяснения: у вас Foo метод, скажем так Задача A, а вы есть Task в нем,скажем так Задача B, теперь под управлением задачи Задача B ваш Задача A в ожидании задача B результат.И вы задаете переменную результата для своего возвращения Task что это Задач "А",, потому что задача B не возвращает задачу возвращает string. Рассматривайте это:

если вы определяете свой результат следующим образом:

Task result = Foo(5);

вы не получите любая ошибка.Но если вы определяете это так:

string result = Foo(5);

вы получите:

не удается неявно преобразовать тип System.Нарезка резьбы.Задачи.Задача ' to 'string'

но если добавить await ключевые слова:

string result = await Foo(5);

снова вы не получите никаких ошибок.Потому что он будет ждать результата (строки) и назначить его Вашей переменной результата.Поэтому в последнюю очередь рассмотрим это, если вы добавите две задачи в свой Foo Метод:

private static async Task<string> Foo(int seconds)
{
    await Task.Run(() =>
        {
            for (int i = 0; i < seconds; i++)
            {
                Console.WriteLine("Thread ID: {0}, second {1}.", Thread.CurrentThread.ManagedThreadId, i);
                Task.Delay(TimeSpan.FromSeconds(1)).Wait();
            }

            // in here don't return anything
        });

   return await Task.Run(() =>
        {
            for (int i = 0; i < seconds; i++)
            {
                Console.WriteLine("Thread ID: {0}, second {1}.", Thread.CurrentThread.ManagedThreadId, i);
                Task.Delay(TimeSpan.FromSeconds(1)).Wait();
            }

            return "Foo Completed.";
        });
}

и если вы запустите приложение, вы получите те же результаты.(WaitingForActivation) потому что теперь ваша задача A ждет этих двух задач.


вы должны вызвать функцию Foo.Wait () в какой-то момент вашего кода. Это означает, что перед продолжением выполнения кода необходимо дождаться результата выполнения.


я преодолеваю эту проблему, если кто-то заинтересован. В методе myMain я вызвал свой метод readasync как

Dispatcher.BeginInvoke(new ThreadStart(() => ReadData()));

теперь все хорошо для меня.