Асинхронное программирование на C #

#c#

#c#

Вопрос:

У меня есть мой файл Program.cs:

 using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace AsyncTest
{
    class Program
    {

        static async Task Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            var interesting = new InterestingObject();

            List<int> list;
            List<int> alsoList;

            list = await interesting.GenerateListAsync();
            alsoList = interesting.GenerateList();

            Console.WriteLine("Done! :)");

            list    .ForEach(xs => Console.WriteLine(xs));
            alsoList.ForEach(xs => Console.WriteLine (xs));

        }

    }
}
  

И вот код для InterestingObject:

 using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncTest
{
    public class InterestingObject
    {
        public InterestingObject()
        {
        }

        public List<int> GenerateList()
        {

            Console.WriteLine("Gonna generate the list!");

            var list = new List<int>();
            int i = 0;
            while (i < 5)
            {

                Random random = new Random();
                list.Add(random.Next());
                Console.WriteLine("Generated a new int!");
                VeryHeavyCalculations();

                i  ;
            }

            return list;

        }

        public async Task<List<int>> GenerateListAsync()
        {

            Console.WriteLine("Gonna generate the list async!");

            var list = new List<int>();
            int i = 0;
            while (i < 5)
            {

                Random random = new Random();
                list.Add(random.Next ());
                Console.WriteLine("Generated a new int asyncronously!");
                await Task.Run(() => VeryHeavyCalculations());

                i  ;
            }

            return list;

        }

        public void VeryHeavyCalculations()
        {
            Thread.Sleep (1000);
        }
    }
}
  

Я ожидаю, что list = await interesting.GenerateListAsync(); во время alsoList = interesting.GenerateList(); выполнения будет выполняться асинхронно, эффективно регистрируя выходные данные GenerateList в моей консоли, пока GenerateListAsync выполняется то же самое, или чтобы увидеть GenerateListAsync завершение почти мгновенно по GenerateList завершении.

Однако, заглядывая в консоль, я вижу, что мое приложение запущено, GenerateListAsync а затем запускается GenerateList после этого.

Я делаю это неправильно, но ни одного источника не было достаточно для решения этой проблемы.

Комментарии:

1. Он выполняется асинхронно, но код не продолжается до окончания await . Если вы хотите завершить эту операцию и затем двигаться дальше, то не await выполняйте задачу до некоторого момента позже в вашем коде.

2. Это вспомогательный ответ на ваш вопрос. Вы делаете new Random() в цикле. Для вас это ничем хорошим не закончится. Вы просто собираетесь создать его с тем же исходным кодом, и он будет генерировать те же числа.

3. @Crowcoder вы хотите сказать, что компилятор использует предварительный просмотр, чтобы увидеть, есть ли await впереди, и он будет запускать их асинхронно, пока он выполняет весь предшествующий ему код?

4. Нет. Вы могли бы рассмотреть возможность загрузки LINQPad и ознакомления с этим руководством по библиотеке примеров: Интерактивное руководство по асинхронности в C # 5, обновленное для Framework 4.5 RTM

Ответ №1:

Я ожидаю, что list = await interesting.GenerateListAsync(); будет выполняться асинхронно во время alsoList = interesting.GenerateList(); выполнения,

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

 List<int> list;
List<int> alsoList;

var pending = interesting.GenerateListAsync(); // no await
alsoList = interesting.GenerateList();
list = await pending; // essentially "joins" at this point... kind of
  

Обратите внимание, что async и параллелизм — это разные вещи; их можно использовать вместе, но по умолчанию это происходит не так. Также обратите внимание: не весь код разработан для обеспечения одновременного использования, поэтому вам не следует делать такого рода вещи, не зная, нормально ли использовать параллельные вызовы в определенном API.

Комментарии:

1. Ах, я думаю, я только сейчас понял .. await используется не для указания чему-либо выполняться асинхронно, а для ожидания операций, которые выполняются асинхронно?

2. @Vanitas точно

3. Итак, что тогда произойдет, если вы используете async при объявлении элемента объекта? Есть ли у вас источник, который подробно объясняет, что именно происходит?

4. @Vanitas async буквально ничего не делает, кроме включения await ключевого слова; что касается того, что происходит, когда вы await — это действительно сложная история

5. Поддержано. Не понимаю, в чем разница. Это краткое и точное объяснение того, как работает шаблон async / await , который был проблемой в исходном сообщении.

Ответ №2:

В дополнение к ответу взгляните на await (ссылка на C #)

Оператор await применяется к задаче в асинхронном методе, чтобы вставить точку приостановки в выполнение метода до завершения ожидаемой задачи. это причина, по которой в вашем приложении выполняется GenerateListAsync, а затем выполняется GenerateList впоследствии. Чтобы запустить GenerateListAsync асинхронно, вам нужно принять возвращаемое значение GenerateListAsync в переменной задачи, а затем вызвать GenerateList и после этого использовать метод await для GenerateListAsync.

например

 Task <List<int>> longRunningTask = interesting.GenerateListAsync();
        alsoList = interesting.GenerateList();
        list = await longRunningTask;
  

Комментарии:

1. » Для асинхронного запуска GenerateListAsync … » — Вы путаете асинхронность с параллелизмом. Оно выполняется асинхронно (при условии, что реализовано как таковое) даже с await .