concurrency - 如何让 Promise 变得懒惰?
问题描述
open System
open System.Threading
open Hopac
open Hopac.Infixes
let hello what = job {
for i=1 to 3 do
do! timeOut (TimeSpan.FromSeconds 1.0)
do printfn "%s" what
}
run <| job {
let! j1 = Promise.start (hello "Hello, from a job!")
do! timeOut (TimeSpan.FromSeconds 0.5)
let! j2 = Promise.start (hello "Hello, from another job!")
//do! Promise.read j1
//do! Promise.read j2
return ()
}
Console.ReadKey()
Hello, from a job!
Hello, from another job!
Hello, from a job!
Hello, from another job!
Hello, from a job!
Hello, from another job!
这是Hopac 文档中的示例之一。从我在这里可以看到,即使我没有显式调用Promise.read j1
或Promise.read j2
函数仍然运行。我想知道是否可以推迟执行承诺的计算,直到它们实际运行?或者我应该使用lazy
传播惰性值的目的吗?
查看文档,Hopac 的承诺似乎应该是懒惰的,但我不确定这种懒惰应该如何表现出来。
解决方案
为了演示懒惰,请考虑以下示例。
module HopacArith
open System
open Hopac
type S = S of int * Promise<S>
let rec arith i : Promise<S> = memo <| Job.delay(fun () ->
printfn "Hello"
S(i,arith (i+1)) |> Job.result
)
let rec loop k = job {
let! (S(i,_)) = k
let! (S(i,k)) = k
printfn "%i" i
Console.ReadKey()
return! loop k
}
loop (arith 0) |> run
Hello
0
Hello
1
Hello
2
如果没有记住这些值,则每次按下 enter 时,Hello
每次迭代都会打印两个 s。memo <|
如果删除,则可以看到此行为。
还有一些值得进一步说明的观点。的目的Promise.start
并不是专门为某些工作获得记忆行为。Promise.start
类似于Job.start
如果您使用let!
或绑定一个值>>=
,它不会阻塞工作流,直到工作完成。但是,与 相比Job.start
,Promise.start
确实提供了一个选项,可以通过绑定嵌套值来等待计划作业完成。与常规 .NET 任务不同Job.start
且类似的是,可以从使用 .NET 启动的并发作业中提取值Promise.start
。
最后,这是我在玩 Promise 时发现的一个有趣的花絮。事实证明,将 aJob
转换为 an 的一个好方法Alt
是将其转换为Promise
first 然后向上转换。
module HopacPromiseNonblocking
open System
open Hopac
open Hopac.Infixes
Alt.choose [
//Alt.always 1 ^=>. Alt.never () // blocks forever
memo (Alt.always 1 ^=>. Alt.never ()) :> _ Alt // does not block
Alt.always 1 >>=*. Alt.never () :> _ Alt // same as above, does not block
Alt.always 2
]
|> run
|> printfn "%i" // prints 2
Console.ReadKey()
取消注释第一种情况会导致程序永远阻塞,但是如果您首先记住表达式,那么如果使用常规替代方案,就有可能获得回溯行为。
推荐阅读
- angular - Angular Universal 使用无服务器部署到 AWS Lambda,而不是在 dist/browser 中获取 js 文件
- sqlite - 计算列中的相似条目
- postgresql - Postgres 9.6在存在并行工作者时在聚合后收集节点完成
- javascript - 在手机上按住按钮时如何防止附近的文本选择?
- python - 在 Django 中访问多级 json 数据
- python - 如何修复 ValueError:使用回调保存权重后加载权重时轴与数组不匹配。ModelCheckpoint
- c - 如何使用 cat 命令将文件解析为参数
- amazon-web-services - 为 aws lambda 提供创建和删除警报所需的权限
- linux - 如何获取任何命令/任务(例如:Ansible - Yum Install)/stdout 输出,即漂亮的打印或美化/Lint 对齐输出
- java - Swagger Springfox - 如何为查询参数列表生成模式类型数组