为什么必须包装Async< T>进入另一个异步工作流程,让它? [英] Why do I have to wrap an Async<T> into another async workflow and let! it?

查看:90
本文介绍了为什么必须包装Async< T>进入另一个异步工作流程,让它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图了解F#中的异步工作流,但发现其中一部分我确实不了解.

I'm trying to understand async workflows in F# but I found one part that I really don't understand.

以下代码可以正常工作:

The following code works fine:

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)

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

I define a async workflow where TryOpenAsync returns a Task<StreamOpenResult> type. I convert it to Async<StreamOpenResult> with Async.AwaitTask. (Side quest: "Await"Task? It doesn't await it just convert it, does it? I think it has nothing to do with Task.Wait or the await keyword). I "await" it with let! and return it. To start the workflow I use RunSynchronously which should start the workflow and return the result (bind it). On the result I check if the Stream is Found or not.

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

But now to my first question. Why do I have to wrap the TryOpenAsync call in another async computation and let! ("await") it? E.g. the following code does not work:

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

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

我认为AwaitTask使它成为Async<T>,并且RunSynchronously应该启动它.然后使用结果.我想念什么?

I thought the AwaitTask makes it an Async<T> and RunSynchronously should start it. Then use the result. What do I miss?

我的第二个问题是,为什么会有任何异步让我们来!"功能可用吗?也许是因为它不起作用或更好,为什么它不能与以下代码一起起作用?

My second question is why is there any "Async.Let!" function available? Maybe because it does not work or better why doesn't it work with the following code?

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)

我只是将TryOpenAsync插入为参数,但是它不起作用.说不行,是指整个FSI都将挂起.因此,这与我的async/"await"有关.

I just insert the TryOpenAsync as a parameter but it does not work. By saying does not work I mean the whole FSI will hang. So it has something to do with my async/"await".

-更新:

FSI中的工作代码结果:

Result of working code in 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

FSI中的代码无效的结果:

Result of not working code in FSI:

>

您将无法再在FSI中执行任何操作

And you cannot execute anything in the FSI anymore

-更新2

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

I'm using Streamstone. Here the C# example: 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

and here the Stream.TryOpenAsync: https://github.com/yevhen/Streamstone/blob/master/Source/Streamstone/Stream.Api.cs#L192

推荐答案

在不知道Streampartition是什么以及它们如何工作的情况下,我无法告诉您为什么第二个示例不起作用.

I can't tell you why the second example doesn't work without knowing what Stream and partition are and how they work.

但是,我想借此机会指出,这两个示例并非完全等同..

However, I want to take this opportunity to point out that the two examples are not strictly equivalent.

F#async有点像做什么的食谱".当您编写async { ... }时,所得到的计算只是坐在那里,实际上并没有做任何事情.它更像是声明一个函数,而不是发出一个命令.只有当您通过调用Async.RunSynchronouslyAsync.Start之类的东西启动"它时,它才真正运行.一个必然的结果是,您可以多次启动相同的异步工作流,并且每次都会成为一个新的工作流.与IEnumerable的工作原理非常相似.

F# async is kind of like a "recipe" for what to do. When you write async { ... }, the resulting computation is just sitting there, not actually doing anything. It's more like declaring a function than like issuing a command. Only when you "start" it by calling something like Async.RunSynchronously or Async.Start does it actually run. A corollary is that you can start the same async workflow multiple times, and it's going to be a new workflow every time. Very similar to how IEnumerable works.

C#Task更像是对已经在运行的异步计算的引用".一旦调用Stream.TryOpenAsync(partition),计算就会开始,并且在任务实际开始之前就不可能获得Task实例.您可以多次await生成的Task,但是每个await都不会重新尝试打开流.实际上,只有第一个await会等待任务的完成,而随后的每个await都会返回给您同样的记忆结果.

C# Task, on the other hand, is more like a "reference" to an async computation that is already running. The computation starts as soon as you call Stream.TryOpenAsync(partition), and it's impossible to obtain a Task instance before the task actually starts. You can await the resulting Task multiple times, but each await will not result in a fresh attempt to open a stream. Only the first await will actually wait for the task's completion, and every subsequent one will just return you the same remembered result.

在异步/反应式语言中,您将F#async称为冷",而将C#Task称为热".

In the async/reactive lingo, F# async is what you call "cold", while C# Task is referred to as "hot".

这篇关于为什么必须包装Async&lt; T&gt;进入另一个异步工作流程,让它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆