首页 > 解决方案 > 等效于 F# 中的 C# async main

问题描述

我想知道mainF# 中的 C# async 相当于什么。更重要的是,是否有一种特殊的方式可以在 F# 程序中使用/使用异步方法,main还是只是等待完成的问题?

更具体地说,假设我们正在使用 .NET Core 通用主机。

在 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. “使主要异步有什么意义?”

举例来说,异步main似乎主要是为了让其他地方以main异步方式调用成为可能(在那些main不是真正“主要”的情况下,即单元测试等)。

在 F# 的情况下,我想至少有 2 件事阻止了一个从返回异步计算的事情main

  1. 对状态代码强制执行 int 返回类型的 EntryPointAttribute ......对吗?
  2. 编译器可能没有准备好将异步计算作为程序的退出值来处理......对吗?

标签: f#async-awaitf#-async

解决方案


AFAIK 在 F# 中没有异步主等效项。

如果您查看幕后的 C# 实现,它看起来像这样:

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

Program.Main 是异步主程序。

根据所使用的 SynchronizationContext ,我个人觉得这种模式有点可怕。

为了模拟 async main 我会:

let theAsyncTask : Async<int> = ...

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

theAsyncTask是实际要做的工作,嵌入式async切换到线程池以便main线程可以安全地阻塞并等待结果。


推荐阅读