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

из моего понимания одна из главных вещей, что 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;
}

20 ответов


при использовании 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) участвует.


далее к другим ответам, посмотрите на ожидание (ссылка на C#)

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

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

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";
}

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

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

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

совсем нет.

//Я не поняла, почему этот метод должен быть помечен как "асинхронность'.

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

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

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

/ / выполняется ли это на фоне нить?

нет.


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


объяснение

вот краткий пример async / await на высоком уровне. Есть еще много деталей, которые нужно рассмотреть.

Примечание: Task.Delay(1000) имитирует выполнение работы в течение 1 секунды. Я думаю, что лучше всего думать об этом как о ожидании ответа от внешнего ресурса. Поскольку наш код ожидает ответа, система может отложить запущенную задачу в сторону и вернуться к ней после ее завершения. Между тем, он может сделать некоторую другую работу над этим нитка.

в приведенном ниже примере первый блок делает именно это. Он немедленно запускает все задачи (Task.Delay lines) и устанавливает их в сторону. Код будет приостановлен на await a линия до 1-секундной задержки, прежде чем перейти к следующей строке. С b, c, d и e все начали выполняться почти в то же время, что и a (из-за отсутствия ждут), они должны закончить примерно в то же время в этом случай.

в приведенном ниже примере второй блок запускает задачу и ждет ее завершения (вот что await does) перед запуском последующих задач. Каждая итерация занимает 1 секунду. The await приостанавливает программу и ждет результата, прежде чем продолжить. В этом основное отличие первого и второго блоков.

пример

Console.WriteLine(DateTime.Now);

// This block takes 1 second to run because all
// 5 tasks are running simultaneously
{
    var a = Task.Delay(1000);
    var b = Task.Delay(1000);
    var c = Task.Delay(1000);
    var d = Task.Delay(1000);
    var e = Task.Delay(1000);

    await a;
    await b;
    await c;
    await d;
    await e;
}

Console.WriteLine(DateTime.Now);

// This block takes 5 seconds to run because each "await"
// pauses the program until the task finishes
{
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
}
Console.WriteLine(DateTime.Now);

выход:

5/24/2017 2:22:50 PM
5/24/2017 2:22:51 PM (First block took 1 second)
5/24/2017 2:22:56 PM (Second block took 5 seconds)

дополнительная информация о SynchronizationContext

Примечание: здесь все становится немного туманным для меня, поэтому, если я ошибаюсь в чем-либо, пожалуйста, исправьте меня, и я обновлю ответ. Важно иметь базовое понимание того, как это работает, но вы можете обойтись без того, чтобы быть экспертом в этом, пока вы никогда не используете ConfigureAwait(false), хотя вы, вероятно, потеряете некоторую возможность для оптимизации, я полагаю.

есть один аспект этого, который делает концепцию async / await несколько сложнее понять. Это тот факт, что в этом примере все это происходит в одном потоке (или, по крайней мере, то, что кажется одним и тем же потоком в отношении его SynchronizationContext). По умолчанию await восстановит контекст синхронизации исходного потока, на котором он работал. Например, в ASP.NET у вас есть HttpContext, который привязан к потоку при поступлении запроса. Этот контекст содержит вещи, специфичные для исходного Http-запроса, такие как исходный Объект запроса, который имеет такие вещи, как язык, IP адреса, заголовки и т. д. Если вы переключаете потоки на полпути через обработку чего-то, вы потенциально можете попытаться вытащить информацию из этого объекта на другом HttpContext, который может быть катастрофическим. Если вы знаете, что не будете использовать контекст для чего-либо, вы можете выбрать "не заботиться" об этом. Это в основном позволяет вашему коду работать в отдельном потоке без приведения контекста с ним.

как вы достичь этого? По умолчанию await a; код на самом деле делает предположение, что вы хотите, чтобы захватить и восстановить контекст:

await a; //Same as the line below
await a.ConfigureAwait(true);

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

await a.ConfigureAwait(false);

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

это сбивает с толку? Да, черт возьми! Ты можешь это понять? Возможно! Как только вы поймете концепции, перейдите к объяснениям Стивена Клири, которые, как правило, больше ориентированы на кого-то с техническим пониманием асинхронности/ожидания.


отображение приведенных выше объяснений в действии в простой консольной программе -

class Program
{
    static void Main(string[] args)
    {
        TestAsyncAwaitMethods();
        Console.WriteLine("Press any key to exit...");
        Console.ReadLine();
    }

    public async static void TestAsyncAwaitMethods()
    {
        await LongRunningMethod();
    }

    public static async Task<int> LongRunningMethod()
    {
        Console.WriteLine("Starting Long Running method...");
        await Task.Delay(5000);
        Console.WriteLine("End Long Running method...");
        return 1;
    }
}

и выход:

Starting Long Running method...
Press any key to exit...
End Long Running method...

таким образом,

  1. Main запускает длительный метод с помощью TestAsyncAwaitMethods. Это немедленно возвращается без остановки текущего потока, и мы сразу видим "нажмите любую клавишу для выхода" сообщение
  2. все это время, LongRunningMethod работает в фоновом режиме. После его завершения, еще одна нить от Threadpool поднимает этот контекст и отображает окончательное сообщение

таким образом, не поток блокируется.


Я думаю, что вы выбрали плохой пример с System.Threading.Thread.Sleep

точки async задача состоит в том, чтобы позволить ему выполняться в фоновом режиме без блокировки основного потока, например,DownloadFileAsync

System.Threading.Thread.Sleep Это не то, что" делается", он просто спит, и поэтому ваша следующая строка достигается через 5 секунд ...

прочитайте эту статью, я думаю, что это отличное объяснение async и await концепция: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx


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

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);
        }
    }
}

этот ответ призван выработать конкретные информация ASP.NET.

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

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

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


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

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

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

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


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

    // 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;
    }

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

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

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

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;
    }   

}

трассировка, поступающая с выхода Окно: enter image description here


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;
    }
}

как я понимаю, это также, должен быть третий термин, добавленный к смеси:Task.

Async - это просто квалификатор, который вы помещаете в свой метод, чтобы сказать, что это асинхронный метод.

Task возвращение . Он выполняется асинхронно.

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

если вместо этого вы назначаете возвращение Ан async функция (ie Task) переменной, когда выполнение кода достигает этой строки, это просто по-прежнему мимо этой строки в окружающей функции пока the Task выполняется асинхронно.


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

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

  • вопрос самоанализ (обучение саке): 1 мин

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

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

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

  • куда дальше?

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

на этом изображении просто сосредоточьтесь на #6 enter image description here

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

вызывающий AccessTheWebAsync () не сделал ничего, кроме ожидания(он мог бы выполнить некоторые внутренние задачи, а затем ждать, если это необходимо). Поэтому вызывающий абонент ждет 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; }

мы упоминали await или async? Нет. Вызовите вышеуказанный метод, и вы получите задачу. Который вы можете контролировать. Вы уже знаете, что возвращает задача.. целое число.

  • вызов задачи немного сложнее. Назовем 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" в качестве префикса (стандарт кодирования). Далее читает позже здесь

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

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

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

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

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

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

easypeasy!

  1. EntityFrameWork nuget (он имеет QueryableExtensions)
  2. пространство имен = Microsoft.EntityFrameworkCore

код изменился такой

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

    Contract GetContract(int contractnumber)

    to

    async Task<Contract> GetContractAsync(int contractnumber)

  2. метод вызова также пострадал:GetContractAsync(123456); называлась GetContractAsync(123456).Result;

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

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

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


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

в этой статье MDSN: асинхронное программирование с async и await (C#) явно объясняет это:

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


в следующем коде метод HttpClient GetByteArrayAsync возвращает задачу getContentsTask. Задача-это обещание создать фактический массив байтов, когда задача будет завершена. Оператор await применяется к getContentsTask для приостановки выполнения в SumPageSizesAsync до завершения getContentsTask. Тем временем управление возвращается вызывающему объекту SumPageSizesAsync. Когда getContentsTask завершен, выражение await вычисляется в массив байтов.

private async Task SumPageSizesAsync()
{
    // To use the HttpClient type in desktop apps, you must include a using directive and add a 
    // reference for the System.Net.Http namespace.
    HttpClient client = new HttpClient();
    // . . .
    Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
    byte[] urlContents = await getContentsTask;

    // Equivalently, now that you see how it works, you can write the same thing in a single line.
    //byte[] urlContents = await client.GetByteArrayAsync(url);
    // . . .
}

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

1) ключевое слово Async включает await, и это все, что он делает. Ключевое слово Async не запускает метод в отдельном потоке. Метод beginning f async запускается синхронно, пока не попадет в ожидание для трудоемкой задачи.

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

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

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

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

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

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

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 подключен. Я хотел бы поделиться с вами практическим опытом, который вы должны знать, прежде чем использовать этот шаблон дизайна.

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

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

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.ФСЛ.

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


Ниже приведен код, который читает файл excel, открывая диалоговое окно, а затем использует асинхронный и ждать, чтобы запустить асинхронный код, который читает по одной строке из excel и привязывается к сетке

    namespace EmailBillingRates
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        lblProcessing.Text = "";
    }

    private async void btnReadExcel_Click(object sender, EventArgs e)
    {
        string filename = OpenFileDialog();

        Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
        Microsoft.Office.Interop.Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(filename);
        Microsoft.Office.Interop.Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1];
        Microsoft.Office.Interop.Excel.Range xlRange = xlWorksheet.UsedRange;
        try
        {
            Task<int> longRunningTask = BindGrid(xlRange);
            int result = await longRunningTask;

        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message.ToString());
        }
        finally
        {
            //cleanup  
           // GC.Collect();
            //GC.WaitForPendingFinalizers();

            //rule of thumb for releasing com objects:  
            //  never use two dots, all COM objects must be referenced and released individually  
            //  ex: [somthing].[something].[something] is bad  

            //release com objects to fully kill excel process from running in the background  
            Marshal.ReleaseComObject(xlRange);
            Marshal.ReleaseComObject(xlWorksheet);

            //close and release  
            xlWorkbook.Close();
            Marshal.ReleaseComObject(xlWorkbook);

            //quit and release  
            xlApp.Quit();
            Marshal.ReleaseComObject(xlApp);
        }

    }

    private void btnSendEmail_Click(object sender, EventArgs e)
    {

    }

    private string OpenFileDialog()
    {
        string filename = "";
        OpenFileDialog fdlg = new OpenFileDialog();
        fdlg.Title = "Excel File Dialog";
        fdlg.InitialDirectory = @"c:\";
        fdlg.Filter = "All files (*.*)|*.*|All files (*.*)|*.*";
        fdlg.FilterIndex = 2;
        fdlg.RestoreDirectory = true;
        if (fdlg.ShowDialog() == DialogResult.OK)
        {
            filename = fdlg.FileName;
        }
        return filename;
    }

    private async Task<int> BindGrid(Microsoft.Office.Interop.Excel.Range xlRange)
    {
        lblProcessing.Text = "Processing File.. Please wait";
        int rowCount = xlRange.Rows.Count;
        int colCount = xlRange.Columns.Count;

        // dt.Column = colCount;  
        dataGridView1.ColumnCount = colCount;
        dataGridView1.RowCount = rowCount;

        for (int i = 1; i <= rowCount; i++)
        {
            for (int j = 1; j <= colCount; j++)
            {
                //write the value to the Grid  
                if (xlRange.Cells[i, j] != null && xlRange.Cells[i, j].Value2 != null)
                {
                     await Task.Delay(1);
                     dataGridView1.Rows[i - 1].Cells[j - 1].Value =  xlRange.Cells[i, j].Value2.ToString();
                }

            }
        }
        lblProcessing.Text = "";
        return 0;
    }
}

internal class 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]
        });
    }

этот метод имеет недостатки serval. Ошибки не передаются, и их очень трудно прочитать. Но асинхронные и ждут, чтобы прийти, чтобы помочь нам:

    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");

    }

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

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

Примечание: Async и Await используются С асинхронные вызовы не чтобы сделать эти. Вы должны использовать Задача Libary для этого, как и задач.Работать. )(

вот сравнение между await и none await solutions

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

    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;
    }

вы можете позвонить асинхронный метод без ключевого слова 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 чтобы получить некоторые образцы.

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