.Net Класс задачи - объясните, пожалуйста

Может кто-нибудь объяснить, почему приведенный ниже метод общедоступной асинхронной задачи DoStuff () все еще может работать, ничего не возвращая? Он не говорит о недействительности, поэтому я предположил, что возвращаемый тип должен быть Задача.

Когда я удаляю ключевые слова async и await из метода DoStuff (), компилятор выдает мне "не все пути кода возвращаются значение " ошибка. Однако, если я добавлю ключевые слова async и await, похоже, что тип возвращаемого значения не понадобится, несмотря на отсутствие ключевого слова void в сигнатуре метода. Я не понимаю!

Что такое задача? Microsoft очень плохо это объясняет. Спасибо.

namespace Async_and_Await_Example
{
    class Program
    {
        static void Main(string[] args)
        {
            AsyncAwaitDemo demo = new AsyncAwaitDemo();
            demo.DoStuff();

            for (int i = 0; i < 100; i++)
            {
                Console.WriteLine("Working on the Main Thread...................");
        }
    }
}
public class AsyncAwaitDemo
{
    public async Task DoStuff()
    {
        await Task.Run(() =>
        {
            CountToFifty();
        });
    }

    private static async Task<string> CountToFifty()
    {
        int counter;

        for (counter = 0; counter < 51; counter++)
        {
            Console.WriteLine("BG thread: " + counter);
        }

        return "Counter = " + counter;
    }
}

}


person Dude    schedule 19.06.2015    source источник


Ответы (6)


Почему приведенный ниже общедоступный метод async Task DoStuff () все еще может работать, ничего не возвращая?

Потому что компилятор это позволяет. Когда вы помечаете метод модификатором async, создается конечный автомат, который фактически возвращает вам Task. Вы можете увидеть это в любом декомпиляторе.

Когда я удаляю ключевые слова async и await из метода DoStuff (), компилятор выдает мне ошибку «не все пути кода возвращают значение».

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

Что такое задача?

Как говорили другие, просто обещание работы, которая будет завершена в будущем. Task может представлять множество вещей, одна из них - асинхронная операция. Магия заключается в async-await ключевых словах, которые идут рядом. Магия компилятора имеет особые отношения с Task, но можно ожидать любого типа, реализующего GetAwaiter метод. Подробнее об этом здесь

person Yuval Itzchakov    schedule 19.06.2015

По сути, задача - это обещание (или будущее). Он «обещает» вам, что запущенный вами асинхронный метод в конечном итоге завершится, выполнив задачу. Объект задачи используется для того, чтобы вы могли получить информацию о том, когда задача выполнена. Также существует общая версия задачи, которая просто обещает вам получить значение, когда задача завершена.

Как только вы запустили асинхронный метод, вы получите обратно объект Task. Метод возвращается почти мгновенно, но фактическая работа, вероятно, заканчивается позже. Затем вы можете дождаться задачи. для завершения, чтобы заблокировать текущий поток, и просто дождитесь завершения асинхронного метода.

Когда вы сами выполняете асинхронное выполнение - а это обычно именно то, что вы хотите делать при вызове асинхронных методов - вы можете ждать этих задач, используя ключевое слово await в объекте задачи. По сути, это приостанавливает асинхронный метод, в котором вы сейчас находитесь, и возвращает выполнение, как только задача, которую вы ожидаете, завершится.

Ключевое слово await доступно только в асинхронных методах, о чем свидетельствует спецификатор метода async. Эти методы автоматически возвращают объект задачи в качестве возвращаемого значения: если вы не возвращаете ничего явно из асинхронного метода, он возвращает объект Task; если вы возвращаете объект типа T из асинхронного метода, он фактически возвращает объект Task<T>, которого вы можете ожидать. Task<T> типов можно затем «распаковать» после выполнения задачи. Это позволяет получить фактический объект типа T.

Наконец, async методы также могут ничего не возвращать, void, чтобы заставить их «выстрелить и забыть». Если вы вызываете асинхронный метод с типом возвращаемого значения void, он будет выполняться асинхронно («огонь»), но у вас не будет никакого способа узнать, когда он завершится, поскольку у вас нет объекта задачи для ожидания («забыть» ). Вот почему вы хотите избегать async void методов в целом (они также плохо подходят для обработки исключений) и всегда использовать вместо них «настоящие» ожидаемые асинхронные методы (те, которые возвращают некоторый объект задачи). Но вы все равно можете использовать async void метод для запуска асинхронного выполнения без блокировки основного потока. В противном случае вы можете просто заблокировать его, вызвав метод Wait() для задачи.

Для получения дополнительной информации проверьте следующие ссылки:

person poke    schedule 19.06.2015

Это потому, что async/await магия. Хорошо, это не совсем волшебство, но с async/await компилятор переписывает ваш метод так, чтобы он возвращал Task. Так же, как CountToFifty() возвращает Task<string>, но ваш метод возвращает string.

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

Без async / await компилятор не изменяет DoStuff(), поэтому вы должны вернуть объект Task.

person shf301    schedule 19.06.2015

Асинхронные методы не возвращаются немедленно. Метод может запросить внешний источник. Это требует времени - и другой код может работать. Это цель await-async в методе. Таким образом, не всегда необходимо возвращаться в асинхронном методе, когда мы используем ключевое слово await.

Дополнительные сведения см. В Разъяснении задач от DotNetPearls.

person Umair M    schedule 19.06.2015

Как отмечали другие, задача - это «обещание» или «будущее», то есть она представляет собой некоторую операцию, которая может быть завершена в будущем.

Task представляет операции без возвращаемых значений, а Task<T> представляет операции с возвращаемым значением T.

Обратите внимание, что Task полезно (вместо void), потому что операция может завершиться либо успешно, либо с исключением (или отменой), а Task может представлять эти конечные состояния.

Может кто-нибудь объяснить, почему приведенный ниже метод общедоступной async Task DoStuff () все еще может работать, ничего не возвращая?

Ключевое слово async создаст конечный автомат для вашего метода, а конечный автомат создаст объект Task, представляющий этот метод. Если ваш async метод возвращает значение, конечный автомат помещает это возвращаемое значение в Task<T>. Если ваш async метод вызывает исключение, конечный автомат помещает это исключение в _12 _ / _ 13_.

Что такое задача?

Я описал, что Task в контексте _15 _ / _ 16_. Отчасти путаница возникает из-за того, что Task приобретает совсем другое значение при использовании по-другому. Я использую термины Promise Task для асинхронных задач и Delegate Task для задач, выполняемых с кодом.

Задачи, созданные конечным автоматом async, всегда являются задачами-обещаниями. Вообще говоря, асинхронные задачи должны быть await, а не Wait. И вам следует избегать async void (поскольку конечный автомат не может представить метод, он имеет удивительную семантику обработки исключений).

Вы можете найти мое async intro полезным, а также мою статья о передовых методах.

person Stephen Cleary    schedule 19.06.2015

Другой способ взглянуть на это: допустим, у вас есть 4 действия в ответ на HTTP-запрос от клиента.

  1. Внесите заказ в базу данных. Task.Run (PlaceOrder)
  2. Отправьте клиенту письмо с благодарностью. Task.Run (SendEmail)
  3. Отправьте запрос на API вашего центра исполнения. Task.Run (PlaceOrder)
  4. Зарегистрируйте запрос сеанса. Task.Run (LogRequest)

Таким образом, вместо того, чтобы говорить о контрактах, обещаниях, серверах состояний и т. Д., Задача - это многопоточность, которая распределяет работу по всем вашим ядрам / процессорам. У меня 4 ядра и 8 процессоров. Если я поставлю задачу выше, я увижу, что работают все 8 процессоров, и это более чем в два раза быстрее. Это задача.

Стало еще лучше. Сейчас работа идет на всех 8 процессорах, но мы можем сделать ее еще быстрее. Хотя они работают на всех 8 процессорах, они по очереди или стоят в очереди, ожидая завершения друг друга. Скажем, в среднем каждая задача занимает 5 секунд, поэтому мое время ответа клиенту составляет 20 секунд, но мы просто сократили это вдвое. Если я использую async / await, я могу запустить все 4 задачи одновременно, чтобы никто из них не ждал друг друга. Итак, теперь я вижу, что все 8 процессоров работают, но теперь они используют немного больше ЦП, и wow64 их готово.

Но подождите, они все еще были медленными, потому что запрос api для доставки заказа занял 8 секунд, а клиент и другие Задачи должны были дождаться его завершения. Вот где становится действительно хорошо. Не ждите. Ответьте клиенту и поблагодарите его за заказ. Итак, теперь вы просто вернули транзакцию клиенту за 3 миллисекунды, а не за 20 секунд. Оберните попытку / уловку вокруг 4 задач и записывайте все сбои, чтобы кто-то мог их выполнить. Надеюсь, это уже делается, вместо того, чтобы сообщить клиенту, извините, наш почтовый сервер не работает. Я слышал, как некоторые люди называют это «забыть» и что-то еще, и это очень плохо. Это не плохо. Хорошее программирование. Надежное массовое многопоточное / асинхронное программирование давно назрело. Покупка ядер и памяти, которые никогда не используются, и пользователей, которые имеют дело с медленным откликом и ждут, откровенно говоря, им наплевать, уйдет в прошлое.

Это задача / async / await.

var myTask = Task.Run (() => {doSomething}) ;.

person Mark    schedule 17.12.2015