c# - работает - wpf async await




Как и когда использовать «async» и «wait» (14)

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

Они должны сделать асинхронный код легким для записи и чтения, да.

Это то же самое, что и нерестовые потоки фона для выполнения длительной логики?

Не за что.

// Я не понимаю, почему этот метод должен быть помечен как «async».

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

// эта строка достигается после 5 секундного сна из метода DoSomethingAsync (). Разве это не должно быть достигнуто немедленно?

Нет, потому что по умолчанию async методы не выполняются по другому потоку.

// выполняется это в фоновом потоке?

Нет.

Вы можете найти мой async / await ввод полезен. Официальные документы MSDN также необычайно хороши (особенно раздел TAP ), и команда async выпустила отличный FAQ .

По моему мнению, одна из главных вещей, которые async и await , - сделать код легким для записи и чтения - но использует ли он равные нерестилированию фоновых потоков для выполнения длительной логики?

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

// I don't understand why this method must be marked as `async`.
private async void button1_Click(object sender, EventArgs e)
{
    Task<int> access = DoSomethingAsync();
    // task independent stuff here

    // this line is reached after the 5 seconds sleep from 
    // DoSomethingAsync() method. Shouldn't it be reached immediately? 
    int a = 1; 

    // from my understanding the waiting should be done here.
    int x = await access; 
}

async Task<int> DoSomethingAsync()
{
    // is this executed on a background thread?
    System.Threading.Thread.Sleep(5000);
    return 1;
}

использует их равными нерестовым потокам фона для выполнения длительной логики?

В этой статье MDSN: асинхронное программирование с асинхронным и ждущим (C #) объясняет это явно:

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


Async / Await

Acctually Async / Await - это пара ключевых слов, которые являются просто синтаксическим сахаром для создания обратного вызова асинхронной задачи.

Возьмем, например, эту операцию:

    public static void DoSomeWork()
    {
        var task = Task.Run(() =>
        {
            // [RUNS ON WORKER THREAD]

            // IS NOT bubbling up due to the different threads
            throw new Exception();
            Thread.Sleep(2000);

            return "Hello";
        });

        // This is the callback
        task.ContinueWith((t) => {
            // -> Exception is swallowed silently
            Console.WriteLine("Completed");

            // [RUNS ON WORKER THREAD]
        });
    }

Этот метод имеет недостатки в обслуживании. Ошибки не передаются, и читать их крайне трудно. Но Асинк и Авейт пришли помочь нам:

    public async static void DoSomeWork()
    {
        var result = await Task.Run(() =>
        {
            // [RUNS ON WORKER THREAD]

            // IS bubbling up
            throw new Exception();
            Thread.Sleep(2000);

            return "Hello";
        });

        // every thing below is a callback 
        // (including the calling methods)

        Console.WriteLine("Completed");

    }

Ожидание вызовов должно быть в методах Async. Это имеет ряд преимуществ:

  • Возвращает результат задачи
  • автоматически создает обратный вызов
  • проверяет наличие ошибок и позволяет им пузыриться в callstack (только до тех пор, пока не вызовут вызовы в callstack)
  • ждет результата
  • высвобождает основную нить
  • запускает обратный вызов по основному потоку
  • использует рабочий поток из threadpool для задачи
  • упрощает чтение кода
  • и многое другое

ПРИМЕЧАНИЕ . Async и Await используются с асинхронными вызовами, чтобы не делать этого. Для этого вам нужно использовать Task Libary , например Task.Run ().

Вот сравнение между ожиданием и ожиданием решений

Это не асинхронное решение:

    public static long DoTask()
    {
        stopWatch.Reset();
        stopWatch.Start();

        // [RUNS ON MAIN THREAD]
        var task = Task.Run(() => {
            Thread.Sleep(2000);
            // [RUNS ON WORKER THREAD]
        });
        Thread.Sleep(1000);
        // goes directly further
        // WITHOUT waiting until the task is finished

        // [RUNS ON MAIN THREAD]

        stopWatch.Stop();
        // 50 milliseconds
        return stopWatch.ElapsedMilliseconds;
    }

Это асинхронный метод:

    public async static Task<long> DoAwaitTask()
    {
        stopWatch.Reset();
        stopWatch.Start();

        // [RUNS ON MAIN THREAD]

        await Task.Run(() => {
            Thread.Sleep(2000);
            // [RUNS ON WORKER THREAD]
        });
        // Waits until task is finished

        // [RUNS ON MAIN THREAD]

        stopWatch.Stop();
        // 2050 milliseconds
        return stopWatch.ElapsedMilliseconds;
    }

Вы можете вызвать метод async без ключевого слова await, но это означает, что любое исключение здесь проглочено в режиме деблокирования:

    public static Stopwatch stopWatch { get; } = new Stopwatch();

    static void Main(string[] args)
    {
        Console.WriteLine("DoAwaitTask: " + DoAwaitTask().Result + " ms");
        // 2050 (2000 more because of the await)
        Console.WriteLine("DoTask: " + DoTask() + " ms");
        // 50
        Console.ReadKey();
    }

Async и Await не предназначены для параллельных вычислений. Они используются, чтобы не блокировать основной поток. Если речь идет о кандидатах asp.net или windows. Блокирование основного потока из-за сетевого вызова - это плохо. Если вы сделаете это, ваше приложение перестанет отвечать на запросы или может потерпеть крах.

Просмотрите ms docs, чтобы получить несколько примеров.

Надеюсь это поможет;


В дополнение к другим ответам, взгляните на ожидание (C # Reference)

и, более конкретно, в приведенном примере, это немного объясняет вашу ситуацию

Следующий пример Windows Forms иллюстрирует использование ожидания в асинхронном методе WaitAsynchronouslyAsync. Контрастируйте поведение этого метода с поведением WaitSynchronously. Без оператора ожидания, примененного к задаче, WaitSynchronously выполняется синхронно, несмотря на использование модификатора async в его определении и вызов Thread.Sleep в его теле.

private async void button1_Click(object sender, EventArgs e)
{
    // Call the method that runs asynchronously.
    string result = await WaitAsynchronouslyAsync();

    // Call the method that runs synchronously.
    //string result = await WaitSynchronously ();

    // Display the result.
    textBox1.Text += result;
}

// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window 
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
    await Task.Delay(10000);
    return "Finished";
}

// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
    // Add a using directive for System.Threading.
    Thread.Sleep(10000);
    return "Finished";
}

Вот краткая консольная программа, которая поможет понять, кто последует. Метод «TaskToDo» - это ваш длинный метод, который вы хотите сделать async. Выполнение его запуска Async выполняется методом TestAsync. Метод тестовых циклов просто проходит через задачи TaskToDo и запускает их Async. Вы можете видеть это в результатах, потому что они не завершаются в том же порядке от запуска до запуска - они сообщают о потоке пользовательского интерфейса консоли при их завершении. Упрощенный, но я думаю, что упрощенные примеры лучше всего раскрывают ядро ​​шаблона, чем более привлекательные примеры:

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

namespace TestingAsync
{
    class Program
    {
        static void Main(string[] args)
        {
            TestLoops();
            Console.Read();
        }

        private static async void TestLoops()
        {
            for (int i = 0; i < 100; i++)
            {
                await TestAsync(i);
            }
        }

        private static Task TestAsync(int i)
        {
            return Task.Run(() => TaskToDo(i));
        }

        private async static void TaskToDo(int i)
        {
            await Task.Delay(10);
            Console.WriteLine(i);
        }
    }
}

Все ответы здесь используют Task.Delay () или некоторые другие встроенные функции async. Но вот мой пример, который не использует ни одну из этих асинхронных функций:

    // Starts counting to a large numbewr and then immediately displays message "i'm counting...". 
    // Then it waits for task to finish and displays "finished, press any key".
    static void asyncTest ()
    {
        Console.WriteLine("Started asyncTest()");
        Task<long> task = asyncTest_count();
        Console.WriteLine("Started counting, please wait...");
        task.Wait(); // if you comment this line you will see that message "Finished counting" will be displayed before we actually finished counting.
        //Console.WriteLine("Finished counting to " + task.Result.ToString()); // using task.Result seems to also call task.Wait().
        Console.WriteLine("Finished counting.");
        Console.WriteLine("Press any key to exit program.");
        Console.ReadLine();
    }

    static async Task<long> asyncTest_count()
    {
        long k = 0;
        Console.WriteLine("Started asyncTest_count()");
        await Task.Run(() =>
        {
            long countTo = 100000000;
            int prevPercentDone = -1;
            for (long i = 0; i <= countTo; i++)
            {
                int percentDone = (int)(100 * (i / (double)countTo));
                if (percentDone != prevPercentDone)
                {
                    prevPercentDone = percentDone;
                    Console.Write(percentDone.ToString() + "% ");
                }

                k = i;
            }
        });
        Console.WriteLine("");
        Console.WriteLine("Finished asyncTest_count()");
        return k;
    }

При использовании async и await компилятор генерирует конечный автомат в фоновом режиме.

Вот пример, на котором я надеюсь, что смогу объяснить некоторые детали на высоком уровне:

public async Task MyMethodAsync()
{
    Task<int> longRunningTask = LongRunningOperationAsync();
    // independent work which doesn't need the result of LongRunningOperationAsync can be done here

    //and now we call await on the task 
    int result = await longRunningTask;
    //use the result 
    Console.WriteLine(result);
}

public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation 
{
    await Task.Delay(1000); // 1 second delay
    return 1;
}

Хорошо, так что происходит здесь:

  1. Task<int> longRunningTask = LongRunningOperationAsync(); начинает выполнение LongRunningOperation

  2. Независимая работа выполняется, предположим, что основная тема (Thread ID = 1), а затем await longRunningTask .

    Теперь, если longRunningTask еще не закончен и он все еще запущен, MyMethodAsync() вернется к его вызывающему методу, поэтому основной поток не блокируется. Когда longRunningTask выполняется, поток из ThreadPool (может быть любым потоком) вернется в MyMethodAsync() в его предыдущем контексте и продолжит выполнение (в этом случае печать результата на консоль).

Второй случай заключается в том, что longRunningTask уже завершил свое выполнение, и результат будет доступен. При достижении await longRunningTask у нас уже есть результат, поэтому код будет продолжать выполняться в том же потоке. (в этом случае результат печати на консоль). Конечно, это не относится к приведенному выше примеру, где задействован Task.Delay(1000) .


См. Этот скрипт https://dotnetfiddle.net/VhZdLU (и, если это возможно, улучшить его) для запуска простого консольного приложения, которое показывает использование Task, Task.WaitAll (), async и ожидание операторов в одной и той же программе.

Эта скрипка должна очистить концепцию цикла выполнения.

Вот пример кода

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {               
        var a = MyMethodAsync(); //Task started for Execution and immediately goes to Line 19 of the code. Cursor will come back as soon as await operator is met       
        Console.WriteLine("Cursor Moved to Next Line Without Waiting for MyMethodAsync() completion");
        Console.WriteLine("Now Waiting for Task to be Finished");       
        Task.WaitAll(a); //Now Waiting      
        Console.WriteLine("Exiting CommandLine");       
    }

    public static async Task MyMethodAsync()
    {
        Task<int> longRunningTask = LongRunningOperation();
        // independent work which doesn't need the result of LongRunningOperationAsync can be done here
        Console.WriteLine("Independent Works of now executes in MyMethodAsync()");
        //and now we call await on the task 
        int result = await longRunningTask;
        //use the result 
        Console.WriteLine("Result of LongRunningOperation() is " + result);
    }

    public static async Task<int> LongRunningOperation() // assume we return an int from this long running operation 
    {
        Console.WriteLine("LongRunningOperation() Started");
        await Task.Delay(2000); // 2 second delay
        Console.WriteLine("LongRunningOperation() Finished after 2 Seconds");
        return 1;
    }   

}

Трассировка из окна вывода:


Честно говоря, я по-прежнему считаю, что лучшим объяснением является будущее и обещания в Википедии: http://en.wikipedia.org/wiki/Futures_and_promises

Основная идея заключается в том, что у вас есть отдельный пул потоков, выполняющий задачи асинхронно. При использовании. Однако объект обещает, что он выполнит операцию в течение некоторого времени и даст вам результат, когда вы его попросите. Это означает, что он будет блокироваться, когда вы запросите результат и не закончите, но в противном случае выполните пул потоков.

Оттуда вы можете оптимизировать вещи: некоторые операции могут быть реализованы async, и вы можете оптимизировать такие вещи, как IO файла и сетевую связь, путем объединения последующих запросов и / или их переупорядочения. Я не уверен, что это уже находится в платформе задач Microsoft, но если это не так, это будет одна из первых вещей, которые я бы добавил.

Фактически вы можете реализовать будущий тип шаблона с доходностью в C # 4.0. Если вы хотите точно знать, как это работает, я могу рекомендовать эту ссылку, которая выполняет достойную работу: http://code.google.com/p/fracture/source/browse/trunk/Squared/TaskLib/ . Однако, если вы начнете заниматься этим самостоятельно, вы заметите, что вам действительно нужна поддержка языка, если вы хотите делать все классные вещи - это именно то, что сделала Microsoft.


Этот ответ призван предоставить некоторую информацию, специфичную для ASP.NET.

Используя async / wait в контроллере MVC, можно увеличить использование пула потоков и добиться гораздо большей пропускной способности, как описано в следующей статье,

http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

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


Для быстрого обучения ..

  • Понять поток выполнения метода (со схемой): 3 минуты

  • Вопрос интроспекции (обучение ради): 1 мин.

  • Быстро пройти синтаксический сахар: 5 минут

  • Поделитесь путаницей разработчика: 5 минут

  • Проблема: быстро измените реальную реализацию обычного кода на код Async: 2 минуты

  • Где дальше?

Понять поток выполнения метода (со схемой): 3 минуты

На этом изображении просто сосредоточьтесь на # 6

На шаге # 6: AccessTheWebAsync () закончил работу, которую он может сделать без результата getStringTask. Поэтому AccessTheWebAsync использует ожидающий оператор, чтобы приостановить его прогресс и вернуть управление (выход) вызывающему. AccessTheWebAsync возвращает вызывающей программе задание (возвращаемое значение строки). Задача представляет собой обещание произвести строковый результат. Но когда он вернет звонок? второй вызов снова?

Вызывающий AccessAWebAsync () ничего не делал, кроме как ждать (он мог бы выполнять некоторые внутренние задачи, а затем ждать, если это необходимо). Таким образом, вызывающий абонент ждет AccessTheWebAsync и AccessTheWebAsync ждет GetStringAsync на данный момент.

Помните, что метод уже был возвращен, он не может вернуться снова (второй раз). Итак, как узнает собеседник? Это все о задачах! Задача была возвращена. Задание ожидалось (не метод, а не значение). Значение будет задано в Задаче. Статус задачи будет установлен. Caller просто контролирует задачу. Далее читается позже.

Вопрос интроспекции для изучения: 1 мин.

Давайте немного подкорректируем вопрос:

Как и когда использовать async и await Tasks ?

Поскольку учебная Task автоматически охватывает другую 2. Ради обучения, по крайней мере. Конечно, это ответ на ваш вопрос об async и await .

Быстро пройти синтаксический сахар: 5 минут

  • До конверсии

    internal static int Method(int arg0, int arg1) { int result = arg0 + arg1; IO(); // Do some long running IO. return result; }

  • Другой метод Task-ified для вызова вышеуказанного метода

    internal static Task<int> MethodTask(int arg0, int arg1) { Task<int> task = new Task<int>(() => Method(arg0, arg1)); task.Start(); // Hot task (started task) should always be returned. return task; }

Мы упоминали об ожидании или асинхронности? Нет. Вызовите вышеуказанный метод, и вы получите задание. Что вы можете контролировать. Вы уже знаете, что возвращает задача. Integer.

  • Вызов задачи несколько сложный. Назовем метод MethodTask ()

    internal static async Task<int> MethodAsync(int arg0, int arg1) { int result = await HelperMethods.MethodTask(arg0, arg1); return result; }

Мы ожидаем, что задача будет завершена. Отсюда await . Поскольку мы используем await, мы должны использовать async (обязательный) и MethodAsync с «Async» в качестве префикса (стандарт кодирования). Далее далее читает here

Поделитесь путаницей разработчика: 5 минут

Разработчик ошибся в том, что не выполнил Task но он все еще работает! Попытайтесь понять этот вопрос и только принятый ответ здесь . Надеюсь, вы прочитали и полностью поняли. Аналогично в нашем примере вызов уже построенного MethodAsync() проще, чем реализация этого метода с помощью Task ( MethodTask() ). Большинство разработчиков затрудняют задачу поиска Tasks при преобразовании кода в асинхронный.

Совет. Попробуйте найти существующую реализацию Async (например, MethodAsync или ToListAsync ), чтобы MethodAsync ToListAsync . Поэтому нам нужно иметь дело только с Async и ждать (что легко и довольно похоже на обычный код)

Проблема: быстро изменить реальную реализацию обычного кода для работы Async: 2 минуты

Строка кода, показанная ниже в слое данных, начала прерываться (во многих местах). Потому что мы обновили часть нашего кода с .Net framework 4.2 до ядра .Net. Мы должны были исправить это за 1 час по всему приложению!

var myContract = query.Where(c => c.ContractID == _contractID).First();

очень просто!

  1. EntityFrameWork nuget (имеет QueryableExtensions)
  2. namespace = Microsoft.EntityFrameworkCore

код был изменен следующим образом

var myContract = await query.Where(c => c.ContractID == _contractID).FirstAsync();
  1. Подпись метода изменилась с

    Contract GetContract(int contractnumber)

    в

    async Task<Contract> GetContractAsync(int contractnumber)

  2. вызываемый метод также получил влияние: GetContractAsync(123456); был вызван как GetContractAsync(123456).Result;

  3. Мы изменили его всюду за 30 минут!

Но архитектор сказал нам не использовать библиотеку EntityFrameWork только для этого! упс! драма! Затем мы создали пользовательскую задачу. Который вы знаете как. Все еще легко!

Где дальше? Существует замечательное быстрое видео, которое мы могли бы посмотреть о преобразовании синхронных вызовов в асинхронный в ядре ASP.Net , потому что это, скорее всего, направление, которое можно было бы прочитать после прочтения этого.


На более высоком уровне:

1) Ключевое слово Async позволяет ждать, и это все, что он делает. Ключевое слово Async не запускает метод в отдельном потоке. Асинхронный метод begin f запускается синхронно до тех пор, пока он не достигнет ожиданий по трудоемкой задаче.

2) Вы можете ждать метода, который возвращает Task или Task типа T. Вы не можете ждать по методу async void.

3) В тот момент, когда основные встречные потоки ждут по трудоемкой задаче или когда начинается фактическая работа, основной поток возвращается к вызывающей стороне текущего метода.

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

5) Ожидание выполнения задачи обработки теперь будет выполняться в отдельном потоке из пула потоков.

6) Когда эта задача ожидания будет завершена, весь код под ней будет выполняться отдельным потоком

Ниже приведен пример кода. Выполните его и проверьте идентификатор потока

using System;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncAwaitDemo
{
    class Program
    {
        public static async void AsynchronousOperation()
        {
            Console.WriteLine("Inside AsynchronousOperation Before AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            //Task<int> _task = AsyncMethod();
            int count = await AsyncMethod();

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod Before Await, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            //int count = await _task;

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await Before DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            DependentMethod(count);

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await After DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
        }

        public static async Task<int> AsyncMethod()
        {
            Console.WriteLine("Inside AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            int count = 0;

            await Task.Run(() =>
            {
                Console.WriteLine("Executing a long running task which takes 10 seconds to complete, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(20000);
                count = 10;
            });

            Console.WriteLine("Completed AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            return count;
        }       

        public static void DependentMethod(int count)
        {
            Console.WriteLine("Inside DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId + ". Total count is " + count);
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Started Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            AsynchronousOperation();

            Console.WriteLine("Completed Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            Console.ReadKey();
        }

    }
}

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

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

Вы можете наверняка ждать фоновый поток, используя различные средства:

Device.BeginInvokeOnMainThread(async () => { await AnyAwaitableMethod(); });

// Notice that we do not await the following call, 
// as that would tie it to the foreground thread.
try
{
Task.Run(async () => { await AnyAwaitableMethod(); });
}
catch
{}

Полный код для этих замечаний находится по адресу https://github.com/marcusts/xamarin-forms-annoyances . См. Решение под названием AwaitAsyncAntipattern.sln.

Сайт GitHub также содержит ссылки на более подробное обсуждение этой темы.


public static void Main(string[] args)
{
    string result = DownloadContentAsync().Result;
    Console.ReadKey();
}

// You use the async keyword to mark a method for asynchronous operations.
// The "async" modifier simply starts synchronously the current thread. 
// What it does is enable the method to be split into multiple pieces.
// The boundaries of these pieces are marked with the await keyword.
public static async Task<string> DownloadContentAsync()// By convention, the method name ends with "Async
{
    using (HttpClient client = new HttpClient())
    {
        // When you use the await keyword, the compiler generates the code that checks if the asynchronous operation is finished.
        // If it is already finished, the method continues to run synchronously.
        // If not completed, the state machine will connect a continuation method that must be executed WHEN the Task is completed.


        // Http request example. 
        // (In this example I can set the milliseconds after "sleep=")
        String result = await client.GetStringAsync("http://httpstat.us/200?sleep=1000");

        Console.WriteLine(result);

        // After completing the result response, the state machine will continue to synchronously execute the other processes.


        return result;
    }
}






async-await