如果我在F#中有一个异步无参数工作流程,是否有必要和/或惯用于将其作为一个函数,还是最好保留为原始值?
例如,如果我想定义getRemoteCounterAfterOneSec
,则轮询一些远程计数器源,如果它是
let getRemoteCounterAfterOneSec =
async {
do! Async.Sleep 1000
return! ...
}
或
let getRemoteCounterAfterOneSec () =
async {
do! Async.Sleep 1000
return! ...
}
似乎就像他们应该做同样的事情,只是后者有一个不必要的参数。但是我已经看到这在各种代码中都是两种方式。我还看到行为最终不同的地方:如果使用MailboxProcessor
并且正在执行
let myFunc = mailboxProc.PostAndAsyncReply(fun reply -> GetCount reply)
async {
let! count1 = myFunc
let! count2 = myFunc
}
然后只调用一次mailboxProcessor;第二次它只返回在前一次调用中计算的相同值。但是,如果myFunc
是一个函数,那么它会像你期望的那样两次调用mailboxProcessor。
let myFunc() = mailboxProc.PostAndAsyncReply(fun reply -> GetCount reply)
async {
let! count1 = myFunc()
let! count2 = myFunc()
}
这是实施中的错误吗?这里发生了什么,什么是惯用的?
答案 0 :(得分:2)
当谈到您自己定义的普通异步时,添加()
没有任何效果(好吧,这意味着描述计算的异步是重复构造的,但它有没有实际效果)。
我有时写它只是为了让我的代码更容易理解,或者当异步是递归时(因为当你有递归值时会收到警告)。所以,以下情况很好,但它会给你一个警告:
let rec loop =
async {
do! Async.Sleep 1000
if 1 > 2 then return 1
else return! loop }
PostAndAsyncReply
方法的写法略有不同 - 名称试图反映出来。普通的F#异步方法名为AsyncFooBar
。这个帖子有PostAndAsyncFooBar
表示它第一个帖子然后异步等待,就像这样:
let PostAndAsyncWait () =
post(message)
async { let! sth = wait ()
return sth }
所以,这里它实际上在异步之外发布 - 这使得即使你(语法上)在async
块之外也可以调用该函数。这个名字试图对此非常明确。
(但我个人更喜欢它是否都在异步中,即AsyncPostAndWait
)。