Async в консольном приложении на С#?

У меня есть этот простой код:

public static async Task<int> SumTwoOperationsAsync()
{
    var firstTask = GetOperationOneAsync();
    var secondTask = GetOperationTwoAsync();
    return await firstTask + await secondTask;
}


private async Task<int> GetOperationOneAsync()
{
    await Task.Delay(500); // Just to simulate an operation taking time
    return 10;
}

private async Task<int> GetOperationTwoAsync()
{
    await Task.Delay(100); // Just to simulate an operation taking time
    return 5;
}

Великий. это компилируется.

Но скажу, что у меня консольное приложение, и я хочу запустить код выше (вызов SumTwoOperationsAsync())

 static  void Main(string[] args)
        {
             SumTwoOperationsAsync();
        }

Но я читал, что (при использовании sync) мне нужно полностью синхронизировать вверх и вниз:

Вопрос: Это значит, что моя функция Main должна быть отмечена как async?

Ну, он не может быть, потому что есть ошибка компиляции:

точка входа не может быть помечена модификатором 'async'

Если я понимаю асинхронный материал, поток войдет в функцию Main ---- > SumTwoOperationsAsync ---- > вызовет обе функции и не будет. но до SumTwoOperationsAsync

Что мне не хватает?

Ответ 1

В большинстве типов проектов ваши async "вверх" и "вниз" заканчиваются обработчиком события async void или возвращают Task в вашу инфраструктуру.

Однако приложения консоли не поддерживают это.

Вы можете либо просто выполнить Wait в возвращаемой задаче:

static void Main()
{
  MainAsync().Wait();
  // or, if you want to avoid exceptions being wrapped into AggregateException:
  //  MainAsync().GetAwaiter().GetResult();
}

static async Task MainAsync()
{
  ...
}

или вы можете использовать свой собственный контекст, как тот, который я написал:

static void Main()
{
  AsyncContext.Run(() => MainAsync());
}

static async Task MainAsync()
{
  ...
}

Дополнительная информация для async Консольные приложения в моем блоге.

Ответ 2

Вот самый простой способ сделать это

static void Main(string[] args)
{
    Task t = MainAsync(args);
    t.Wait();
}

static async Task MainAsync(string[] args)
{
    await ...
}

Ответ 3

Как быстрое и очень ограниченное решение:

Задача. Результат

Обе задачи Task.Result и Task.Wait не позволят улучшить масштабируемость при использовании с I/O, поскольку они вызовут блокировку вызывающего потока, ожидая завершения ввода-вывода.

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

notasync

Ответ 4

Мое решение. JSONServer - это класс, который я написал для запуска сервера HttpListener в окне консоли.

class Program
{
    public static JSONServer srv = null;

    static void Main(string[] args)
    {
        Console.WriteLine("NLPS Core Server");

        srv = new JSONServer(100);
        srv.Start();

        InputLoopProcessor();

        while(srv.IsRunning)
        {
            Thread.Sleep(250);
        }

    }

    private static async Task InputLoopProcessor()
    {
        string line = "";

        Console.WriteLine("Core NLPS Server: Started on port 8080. " + DateTime.Now);

        while(line != "quit")
        {
            Console.Write(": ");
            line = Console.ReadLine().ToLower();
            Console.WriteLine(line);

            if(line == "?" || line == "help")
            {
                Console.WriteLine("Core NLPS Server Help");
                Console.WriteLine("    ? or help: Show this help.");
                Console.WriteLine("    quit: Stop the server.");
            }
        }
        srv.Stop();
        Console.WriteLine("Core Processor done at " + DateTime.Now);

    }
}