Это превтаск.Wait () рекомендуется использовать с ContinueWith (из библиотеки задач)?


Так мне недавно сказали, что как я использую мой .ContinueWith для задач не был правильным способом их использования. Я еще не нашел доказательств этого в интернете, поэтому я спрошу вас, ребята, и посмотрю, каков ответ. Вот пример того, как я использую .ContinueWith:

public Task DoSomething()
{
    return Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Step 1");
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("Step 2");
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("Step 3");
    });
}

теперь я знаю, что это простой пример, и он будет работать очень быстро, но просто предположим, что каждая задача выполняет более длительную операцию. Итак, то, что мне сказали, это то, что в the .Продолжайте, вам нужно сказать prevTask.Ждать(); в противном случае вы можете выполнить работу до завершения предыдущей задачи. Это вообще возможно? Я предположил, что моя вторая и третья задача будет выполняться только после завершения их предыдущей задачи.

то, что мне сказали, Как написать код:

public Task DoSomething()
{
    return Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Step 1");
    })
    .ContinueWith((prevTask) =>
    {
        prevTask.Wait();
        Console.WriteLine("Step 2");
    })
    .ContinueWith((prevTask) =>
    {
        prevTask.Wait();
        Console.WriteLine("Step 3");
    });
}
7 88

7 ответов:

Эххх.... Я думаю, что некоторые из текущих ответов чего-то не хватает: что происходит с исключениями?

единственная причина, по которой вы бы позвонили Wait в продолжении было бы наблюдать потенциальное исключение из антецедента в самом продолжении. То же самое произойдет, если вы обратитесь к Result в случае a Task<T> а также, если вы вручную обращались к Exception собственность. Честно говоря, я бы не стал звонить Wait или к Result потому что если есть исключение вы будете платить цену повторного повышения его, который является ненужными накладными расходами. Вместо этого вы можете просто проверить IsFaulted свойство от антецедента Task. Кроме того, вы можете создавать разветвленные рабочие процессы, связывая их в несколько одноуровневых продолжений, которые срабатывают только на основе успеха или неудачи с TaskContinuationOptions.OnlyOnRanToCompletion и TaskContinuationOptions.OnlyOnFaulted.

теперь нет необходимости наблюдать исключение антецедента в продолжении, но вы можете не захотеть, чтобы ваш рабочий процесс продвигался вперед, если, скажем, "Шаг 1" не удалось. В этом случае: указание TaskContinuationOptions.NotOnFaulted на ContinueWith вызовы предотвратили бы логику продолжения от когда-либо даже стрельбы.

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

вы используете его правильно.

создает продолжение, которое выполняется асинхронно когда цель Задание выполнено.

источник: задач.ContinueWith метод (действие как MSDN)

вызова prevTask.Wait() в каждом Task.ContinueWith вызов кажется странным способом повторить ненужную логику-т. е. делать что-то, чтобы быть" супер пупер уверен", потому что вы на самом деле не понимаете, что определенный бит кода делает. Как проверка на нуль просто бросить ArgumentNullException куда бы его все равно бросили.

итак, нет, кто бы вам ни сказал, что это неправильно и, вероятно, не понимает, почему .

кто тебе это сказал?

цитирую MSDN:

создает продолжение, которое выполняется асинхронно, когда цель Задание выполнено.

кроме того, какова была бы цель дальше если бы он не ждал завершения предыдущей задачи?

вы даже можете проверить это самостоятельно:

Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Step 1");
        Thread.Sleep(2000);
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("I waited step 1 to be completed!");
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("Step 3");
    });

С MSDN on Task.Continuewith

возвращенная задача не будет запланирована к выполнению до тех пор, пока текущая задача выполнена. Если критерии указаны через параметр continuationOptions не выполняется, задача продолжения будет отменяется вместо запланированного.

Я думаю, что способ, которым вы ожидаете, что он будет работать в первом примере, является правильным.

вы также можете рассмотреть возможность использования задачи.Запуск вместо задачи.Фабрика.StartNew.

Стивен Клири блоге и Стивена Туба сообщение, что он ссылается объясните различия. Существует также обсуждение в ответ.

По Ссылке Task.Result вы на самом деле делаете подобную логику task.wait

Я повторю то, что многие уже говорили, prevTask.Wait() - это лишнее.

для получения дополнительных примеров можно перейти к цепочка задач с использованием задач продолжения еще одна ссылка ПО Microsoft с хорошими примерами.