Как да използвам ValueTask в C #

Асинхронното програмиране се използва от доста време. През последните години той стана по-мощен с въвеждането на ключовите думи async и await. Можете да се възползвате от асинхронното програмиране, за да увеличите отзивчивостта и производителността на вашето приложение.

Препоръчителният тип връщане на асинхронен метод в C # е Task. Трябва да върнете Task, ако искате да напишете асинхронен метод, който връща стойност. Ако искате да напишете манипулатор на събития, вместо това можете да върнете void. До C # 7.0 асинхронен метод може да върне Task, Task или void. Започвайки с C # 7.0, асинхронен метод също може да върне ValueTask (наличен като част от пакета System.Threading.Tasks.Extensions) или ValueTask. Тази статия представя дискусия за това как можем да работим с ValueTask в C #.

За да работите с примерите за кодове, предоставени в тази статия, трябва да имате Visual Studio 2019 инсталиран във вашата система. Ако все още нямате копие, можете да изтеглите Visual Studio 2019 тук.

Създайте проект за приложение на конзола .NET Core в Visual Studio

Първо, нека създадем проект за приложение на конзола .NET Core в Visual Studio. Ако приемем, че Visual Studio 2019 е инсталиран във вашата система, следвайте стъпките, описани по-долу, за да създадете нов проект за приложение на конзола .NET Core в Visual Studio.

  1. Стартирайте Visual Studio IDE.
  2. Кликнете върху „Създаване на нов проект“.
  3. В прозореца „Създаване на нов проект“ изберете „Console App (.NET Core)“ от показания списък с шаблони.
  4. Щракнете върху Напред.
  5. В показания след това прозорец „Конфигуриране на вашия нов проект“ посочете името и местоположението на новия проект.
  6. Щракнете върху Създаване.

Това ще създаде нов проект за приложение на конзола .NET Core в Visual Studio 2019. Ще използваме този проект, за да илюстрираме използването на ValueTask в следващите раздели на тази статия.

Защо да използвам ValueTask?

Задача представлява състоянието на дадена операция, т.е. дали операцията е завършена, отменена и т.н. Асинхронният метод може да върне или задача, или стойност на задача.

Сега, тъй като Task е референтен тип, връщането на обект на Task от асинхронен метод предполага разпределяне на обекта в управляваната купчина всеки път, когато методът бъде извикан. По този начин, едно предупреждение при използването на Task е, че трябва да разпределяте памет в управляваната купчина всеки път, когато връщате обект на Task от вашия метод. Ако резултатът от операцията, извършена по вашия метод, е налице незабавно или завърши синхронно, това разпределение не е необходимо и следователно става скъпо.

Тук точно на помощ идва ValueTask. ValueTask предоставя две основни предимства. Първо, ValueTask подобрява производителността, защото не се нуждае от разпределяне на купчина, и второ, едновременно е лесно и гъвкаво за изпълнение. Чрез връщане на ValueTask вместо Task от асинхронен метод, когато резултатът е веднага наличен, можете да избегнете ненужните режийни разходи за разпределение, тъй като „T“ тук представлява структура, а структурата в C # е тип стойност (за разлика от „T“ в Task, който представлява клас).

Task и ValueTask представляват два основни „очаквани“ типа в C #. Имайте предвид, че не можете да блокирате ValueTask. Ако трябва да блокирате, трябва да конвертирате ValueTask в задача с помощта на метода AsTask и след това да блокирате върху този референтен обект на задача.

Също така имайте предвид, че всяка ValueTask може да се консумира само веднъж. Тук думата „консумирам“ предполага, че ValueTask може асинхронно да изчаква (изчаква) операцията да завърши или да се възползва от AsTask за преобразуване на ValueTask в задача. ValueTask обаче трябва да се консумира само веднъж, след което ValueTask трябва да се игнорира.

Пример за ValueTask в C #

Да предположим, че имате асинхронен метод, който връща задача. Може да се възползвате от Task.FromResult, за да създадете обекта Task, както е показано в кодовия фрагмент, даден по-долу.

публична задача GetCustomerIdAsync ()

{

    върнете Task.FromResult (1);

}

Горният кодов фрагмент не създава цялата магия на асинхронната машина, но разпределя обект на задача в управляваната купчина. За да избегнете това разпределение, може да искате да се възползвате от ValueTask вместо това, както е показано в кодовия фрагмент, даден по-долу.

публична ValueTask GetCustomerIdAsync ()

{

    връщане на нова ValueTask (1);

}

Следният кодов фрагмент илюстрира синхронно изпълнение на ValueTask.

 публичен интерфейс IRepository

    {

        ValueTask GetData ();

    }

Класът Repository разширява интерфейса IRepository и прилага неговите методи, както е показано по-долу.

    хранилище на публичен клас: IRepository

    {

        публична ValueTask GetData ()

        {

            var стойност = по подразбиране (T);

            връщане на нова ValueTask (стойност);

        }

    }

Ето как можете да извикате метода GetData от метода Main.

static void Main (низ [] аргументи)

        {

            Хранилище на IRepository = ново хранилище ();

            var резултат = хранилище.GetData ();

            if (result.IsCompleted)

                 Console.WriteLine ("Операцията завърши ...");

            друго

                Console.WriteLine ("Операцията е непълна ...");

            Console.ReadKey ();

        }

Нека сега добавим друг метод към нашето хранилище, този път асинхронен метод, наречен GetDataAsync. Ето как би изглеждал модифицираният интерфейс на IRepository.

публичен интерфейс IRepository

    {

        ValueTask GetData ();

        ValueTask GetDataAsync ();

    }

Методът GetDataAsync е реализиран от класа Repository, както е показано в кодовия фрагмент, даден по-долу.

    хранилище на публичен клас: IRepository

    {

        публична ValueTask GetData ()

        {

            var стойност = по подразбиране (T);

            връщане на нова ValueTask (стойност);

        }

        обществена асинхронна ValueTask GetDataAsync ()

        {

            var стойност = по подразбиране (T);

            изчакайте Task.Delay (100);

            възвръщаема стойност;

        }

    }

Кога трябва да използвам ValueTask в C #?

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

Освен това, ако потребителят на асинхронен метод използва Task.WhenAll или Task.WhenAny, използването на ValueTask като тип на връщане в асинхронен метод може да стане скъпо. Това е така, защото ще трябва да конвертирате ValueTask в Task с помощта на метода AsTask, което ще доведе до разпределение, което лесно може да бъде избегнато, ако на първо място е била използвана кеширана задача.

Ето правилото на палеца. Използвайте Task, когато имате парче код, който винаги ще бъде асинхронен, т.е. когато операцията няма да завърши веднага. Възползвайте се от ValueTask, когато резултатът от асинхронна операция вече е наличен или когато вече имате кеширан резултат. Така или иначе, трябва да извършите необходимия анализ на ефективността, преди да разгледате ValueTask.

Как да направите повече в C #:

  • Как да използваме неизменност в C
  • Как да използвам const, readonly и static в C #
  • Как да използвам анотации на данни в C #
  • Как да работите с GUID в C # 8
  • Кога да се използва абстрактен клас срещу интерфейс в C #
  • Как да работя с AutoMapper в C #
  • Как да използвам ламбда изрази в C #
  • Как да работя с Action, Func и Predicate делегати в C #
  • Как да работя с делегати в C #
  • Как да внедрите прост регистратор в C #
  • Как да работя с атрибути в C #
  • Как да работя с log4net в C #
  • Как да приложим шаблона за проектиране на хранилището в C #
  • Как да работя с отражение в C #
  • Как да работя с файлова система за наблюдение в C #
  • Как да извършите мързелива инициализация в C #
  • Как да работите с MSMQ в C #
  • Как да работя с методи за разширение в C #
  • Как да използваме ламбда изрази в C #
  • Кога да се използва летливата ключова дума в C #
  • Как да използвам ключовата дума yield в C #
  • Как да приложим полиморфизъм в C #
  • Как да изградите свой собствен планировчик на задачи в C #
  • Как да работя с RabbitMQ в C #
  • Как да работите с кортеж в C #
  • Проучване на виртуални и абстрактни методи в C #
  • Как да използваме Dapper ORM в C #
  • Как да използвам шаблона за дизайн на мухата в C #