Требуется ли Wait() после использования Task.Factory.StartNew()?

Почти во всей документации, которую я видел по использованию Task.Factory.StartNew в C# 4.0, говорится, что для того, чтобы дождаться завершения Task, вам нужен Wait. Но мое первоначальное тестирование показывает, что в этом нет необходимости. Может ли кто-нибудь еще дать мне подтверждение по этому поводу? Мне любопытно, почему в Интернете и в печатных изданиях так много упоминаний о том, что вы должны позвонить Подождите.

Вот простое консольное приложение, которое показывает, что мне не нужен оператор Wait, поэтому я его закомментировал. Независимо от того, комментирую ли я tsk.Wait(), результат остается тем же.

Ожидаемый результат во всех случаях выглядит следующим образом:

Main thread starting.
After running MyTask. The result is True
After running SumIt. The result is 1
Main thread ending.

Код:

class Program
{
    // A trivial method that returns a result and takes no arguments.
    static bool MyTask()
    {
        Thread.Sleep(2000);
        return true;
    }

    // This method returns the summation of a positive integer
    // which is passed to it.
    static int SumIt(object v)
    {
        int x = (int)v;
        int sum = 0;
        for (; x > 0; x--)
            sum += x;
        return sum;
    }

    static void Main(string[] args)
    {
        Console.WriteLine("Main thread starting.");
        // Construct the first task.
        Task<bool> tsk = Task<bool>.Factory.StartNew(() => MyTask());
        // I found this Wait statement to be completely unnecessary.
        //tsk.Wait();
        Console.WriteLine("After running MyTask. The result is " +
        tsk.Result);
        // Construct the second task.
        Task<int> tsk2 = Task<int>.Factory.StartNew(() => SumIt(1));
        Console.WriteLine("After running SumIt. The result is " +
        tsk2.Result);
        tsk.Dispose();
        tsk2.Dispose();
        Console.WriteLine("Main thread ending.");
        Console.ReadLine();
    }
}

person Tam Bui    schedule 12.01.2011    source источник


Ответы (4)


Если вы просто хотите дождаться завершения задачи, рекомендуется вызвать .Wait(). Для Task (в отличие от Task<T>) это единственный вариант.

Однако для Task<T> есть также .Result, который тоже ждет, и это то, что вы используете. Так что в вашем случае нет необходимости вызывать .Wait().

person Timwi    schedule 12.01.2011
comment
Спасибо, Тимви. У меня пукнул мозг, и я не заметил, что использую Task‹T› вместо Task. Теперь это имеет смысл! - person Tam Bui; 12.01.2011
comment
@stackoverflowuser: Извините, не знал, как это сделать. Готово. - person Tam Bui; 10.08.2011

Одной из важных особенностей Wait является то, что он действует как точка встречи, в которой любое исключение, созданное Task, будет повторно выдано в этой точке. Поскольку текущая реализация Task* заставляет вас наблюдать за любым таким исключением, Wait является хорошим вариантом для этого. Однако вы также можете наблюдать за исключением, запрашивая исключение у экземпляра Task.

*) По-видимому, это будет изменено. Поведение изменено в асинхронной CTP.

person Brian Rasmussen    schedule 12.01.2011

Поскольку согласно этому, доступ к Value из Task гарантирует, что задача завершено, вы правы, что это не требуется.

person Jacob    schedule 12.01.2011
comment
Это правильно. Спасибо, Джейкоб! Моя ошибка заключалась в том, что я забыл, что использую Task‹T› вместо Task. - person Tam Bui; 12.01.2011

Как заявил Тимви, .Result тоже ждет. Поскольку вы используете tsk.Result в своем вызове Console.WriteLine, вы выполняете ожидание как побочный эффект.

Это также зависит от того, сколько времени потребуется для выполнения задачи. Если он очень короткий, вы можете не осознавать необходимость .Wait, потому что кажется, что он всегда заканчивается вовремя. Если вам нужно выполнить задание, прежде чем продолжить, существует опасность его пропустить. Поэтому .Wait следует использовать, даже если в 99% случаев это фактически не приводит к трате времени на ожидание.

person Mark Purdy    schedule 12.01.2011