Эквивалент C # асинхронный основной в F # - PullRequest
2 голосов
/ 17 марта 2019

Мне было интересно, что будет эквивалентно асинхронному C # main в F #. Более того, существует ли особый способ использования / использования асинхронных методов из main в F # -программе или это просто вопрос ожидания завершения?

Чтобы быть более конкретным, скажем, что мы используем .NET Core Generic Host.

В программе на C # main может выглядеть так:

class Program
{
    static async Task Main(string[] args)
    {
         await new HostBuilder().Build().RunAsync();
    }
}

В F # программе мой инстинкт должен был бы сделать что-то вроде этого:

[<EntryPoint>]
let main args =
    HostBuilder().Build.RunAsync().Wait()

... или ...

[<EntryPoint>]
let main args =
    HostBuilder().Build.RunAsync() |> Async.AwaitTask |> Async.RunSynchronously

... или ...

[<EntryPoint>]
let main args = 
    async {
        return HostBuilder().Build.RunAsync() |> Async.AwaitTask
    } |> Async.RunSynchronously

... или просто избегайте асинхронности ... но это не весело ...

[<EntryPoint>]
let main args =
    HostBuilder().Build.Run()

Есть еще несколько формулировок, которые я мог бы показать, но я думаю, что они имеют смысл.

Я думаю, что часть ответа заключается в ответе на эти другие вопросы

  1. "что означает запуск асинхронного основного метода" и
  2. "Какой смысл делать основной асинхронный?"

Исходя из примеров, async main, по-видимому, в основном дает возможность другим местам вызывать main асинхронным способом (в тех случаях, когда main на самом деле не является "основным", т. Е. Модульным тестированием). , так далее).

В случае F # я думаю, что есть как минимум 2 вещи, которые мешают одному просто вернуть асинхронное вычисление из main:

  1. EntryPointAttribute, который обеспечивает тип возвращаемого значения int для кодов состояния ... верно?
  2. Компилятор, вероятно, не готов обрабатывать асинхронные вычисления как выходное значение программы ... верно?

1 Ответ

7 голосов
/ 17 марта 2019

AFAIK, в F # нет асинхронного основного эквивалента.

Если вы посмотрите на реализацию C # за кулисами, это будет выглядеть так:

private static void <Main>(string[] args)
{
   Program.Main(args).GetAwaiter().GetResult();
}

Program.Main - асинхронная главная.

Лично я нахожу этот шаблон немного пугающим в зависимости от того, какой SynchronizationContext используется.

Для эмуляции асинхронного основного я бы:

let theAsyncTask : Async<int> = ...

[<EntryPoint>]
let main argv =
  async {
    do! Async.SwitchToThreadPool ()
    return! theAsyncTask
  } |> Async.RunSynchronously

theAsyncTask - это фактическая работа, которая должна бытьГотово, встроенный async переключается на пул потоков, так что поток main может безопасно заблокировать и дождаться результата.

...