Почему я должен использовать, ожидая, что метод будет выполняться асинхронно. Что делать, если я не хочу дождаться завершения метода до продолжения?

Я весь день наливал документы MSDN, и их философия асинхронного кодирования меня сбивает с толку. Как я понимаю, поток, который вызывает метод async, не будет заблокирован, если вызывается метод async. Тем не менее, async всегда сопрягается с примерами с ожиданием, что, как представляется, отрицает асинхронность, делая так, чтобы внешний метод должен был ждать выполнения кода в любом случае. Должен ли я быть в состоянии вызвать метод async, а затем продолжить выполнение внешнего метода?

Это сценарий, с которым я столкнулся, более или менее:

void reportSomethingHappened(info)
    - Collect info
    - HTTP POST info to logging server (ie. mixpanel, sentry)

И здесь был бы метод вызова:

void largerProcess
    if (whatever)
        reportSomethingHappened();
    bla;
    bla;

Насколько я понимаю, поскольку запросы POST могут выполняться асинхронно, я должен иметь возможность сделать reportSomethingHappened() в async-метод (by AFAIK, ожидание web-запроса и добавление ключевого слова async).

Но для метода largeProcess не нужно ждать (т.е. Ждать) метода отчетности для завершения, чтобы выполнить bla bla. Тем не менее, VS говорит мне, что с помощью метода async я могу либо ждать его, либо произойдет синхронно и блокировать. Разве это не побеждает цель делать это отдельно?

Как написать это, чтобы reportSomethingHappened не блокировал выполнение largeProcess? (Что по сути меня смущает, потому что я думал, что это была точка асинхронности)

Ответ 1

При вызове асинхронного метода он будет работать асинхронно ли вы await возвращаемый задание или нет.

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

async Task LargerProcessAsync()
{
    if (condition)
    {
        await ReportSomethingHappenedAsync();
    }

    // do other stuff
}

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

async Task LargerProcessAsync()
{
    Task task = null;
    if (condition)
    {
        task = ReportSomethingHappenedAsync();
    }

    // do other stuff

    if (task != null)
    {
        await task;
    }
}

Или вы можете просто полностью удалить await. Вы должны понимать, что это может быть опасно, поскольку задача может быть обвинена, и исключение может остаться ненаблюдаемым и почему оно не поощряется. Есть несколько способов сделать это правильно, но они не просты. Вы можете использовать Task.ContinueWith:

void LargerProcess()
{
    if (condition)
    {
        ReportSomethingHappenedAsync().ContinueWith(task => 
        {
            try
            {
                task.Wait();
            }
            catch (Exception exception)
            {
                // handle exception
            }
        })
    }

    // do other stuff
}

Или для ASP.Net смотрите Fire и Forget на ASP.NET