F#中无参数的异步工作流是否应包含在函数中?

时间:2015-04-30 14:31:42

标签: f#

如果我在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()
}

这是实施中的错误吗?这里发生了什么,什么是惯用的?

1 个答案:

答案 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)。