为什么我必须将Async <T>包装到另一个异步工作流中并让它!它?

KCT*_*KCT 5 f# asynchronous let async-workflow

我正在尝试理解F#中的异步工作流程,但我发现有一部分我真的不明白,希望有人可以帮助我.

以下代码工作正常:

let asynWorkflow = async{
    let! result = Stream.TryOpenAsync(partition) |> Async.AwaitTask 
    return result
    } 

let stream = Async.RunSynchronously asynWorkflow
             |> fun openResult -> if openResult.Found then openResult.Stream else Stream(partition)
Run Code Online (Sandbox Code Playgroud)

我定义了一个异步工作流,其中TryOpenAsync返回一个Task类型.我用Async.AwaitTask将它转换为Async.(副任务:"等待"任务?它不等待它只是转换它,是吗?我认为它与Task.Wait或await关键字无关).让我"等待"它!并返回它.要启动工作流,我使用RunSynchronously,它应该启动工作流并返回结果(绑定它).在结果上,我检查是否找不到流.

但现在是我的第一个问题.为什么我必须在另一个异步计算中包装TryOpenAsync调用并让它!("等待")吗?例如,以下代码不起作用:

let asynWorkflow =  Stream.TryOpenAsync(partition) |> Async.AwaitTask  

let stream = Async.RunSynchronously asynWorkflow
             |> fun openResult -> if openResult.Found then openResult.Stream else Stream(partition)
Run Code Online (Sandbox Code Playgroud)

我认为AwaitTask使它成为Async和RunSynchronously应该启动它.然后使用结果.我错过了什么?

我的第二个问题是为什么有"Async.Let!" 功能可用?也许是因为它不起作用或更好,为什么它不适用于以下代码?

let ``let!`` task = async{
    let! result = task |> Async.AwaitTask 
   return result
   } 

let stream = Async.RunSynchronously ( ``let!`` (Stream.TryOpenAsync(partition))  )
         |> fun openResult -> if openResult.Found then openResult.Stream else Stream(partition)
Run Code Online (Sandbox Code Playgroud)

我只是将TryOpenAsync作为参数插入,但它不起作用.通过说不起作用我的意思是整个FSI将挂起.所以它与我的异步/"等待"有关.

---更新:

FSI中工作代码的结果:

>

Real: 00:00:00.051, CPU: 00:00:00.031, GC gen0: 0, gen1: 0, gen2: 0
val asynWorkflow : Async<StreamOpenResult>
val stream : Stream
Run Code Online (Sandbox Code Playgroud)

FSI中无法运行代码的结果:

>
Run Code Online (Sandbox Code Playgroud)

你不能再在FSI中执行任何东西了

---更新2

我正在使用Streamstone.这里是C#示例:https://github.com/yevhen/Streamstone/blob/master/Source/Example/Scenarios/S04_Write_to_stream.cs

这里是Stream.TryOpenAsync:https://github.com/yevhen/Streamstone/blob/master/Source/Streamstone/Stream.Api.cs#L192

The*_*Fox 3

第二个代码块看起来应该对我有用。Stream如果我为和提供虚拟实现,它确实会运行它StreamOpenResult

您应该尽可能避免使用,Async.RunSynchronously因为它违背了异步的目的。将所有这些代码放在一个更大的async块中,然后您将可以访问StreamOpenResult

async {
    let! openResult = Stream.TryOpenAsync(partition) |> Async.AwaitTask  
    let stream = if openResult.Found then openResult.Stream else Stream(partition)
    return () // now do something with the stream
    }
Run Code Online (Sandbox Code Playgroud)

您可能需要在程序的最外边缘放置一个Async.Startor才能实际运行它,但如果您有(或将其转换为 a )并将其传递给可以调用的其他代码(例如 Web 框架),那就更好了它以非阻塞的方式。Async.RunSynchronouslyasyncTask