f#在list.iteri中执行等待异步方法

时间:2016-12-30 11:03:33

标签: asynchronous f# c#-to-f#

我在F#4.0中有以下代码

let processEscalation escalationAction (escalationEvents:UpdateCmd.Record list) =
    printf "%A" Environment.NewLine
    printf "Started %A" escalationAction
    escalationEvents
    |> List.iter ( fun x -> 
        printf "%A" Environment.NewLine
        printf "escalation %A for with action: %A" x.incident_id escalationAction
        service.PostAction(new Models.Action(x.incident_id, escalationAction, "escalated")) 
        |> Async.AwaitTask
        |> ignore)


let ComposeEscalation() = 
    let escalationlevels = ["ESC1 REACHED"; "ESC2 REACHED"; "ESC3 REACHED"]
    escalationlevels 
    |> List.map getEscalationEvents
    |> List.iteri (fun i x -> processEscalation escalationlevels.[i] x)

其中以下行是对返回Task

的C#异步方法的调用
service.PostAction(new Models.Action(x.incident_id, escalationAction, "escalated"))

撰写升级方法调用processEcalation三次。 但是,第二个呼叫在第一个呼叫完成之前开始。 我怎样才能确保最后一行list.iteri等待并按顺序处理它们? 也许processEcalation应该是异步计算表达式?

1 个答案:

答案 0 :(得分:4)

Async.AwaitTask的作用是返回Async计算,可用于等待任务完成。在你的情况下,你永远不会对它做任何事情,所以循环只进行到下一次迭代。

你想要这样的东西:

service.PostAction(new Models.Action(x.incident_id, escalationAction, "escalated")) 
|> Async.AwaitTask
|> Async.RunSynchronously
|> ignore

这应该具有你期望的效果,尽管肯定有更好,更可组合的表达这种逻辑的方式。

编辑:我的意思是这样的,与核心Async.Parallel功能相对应:

module Async = 

    let sequential (asyncs: seq<Async<'t>>) : Async<'t []> = 
        let rec loop acc remaining = 
            async {
                match remaining with
                | [] -> return Array.ofList (List.rev acc)
                | x::xs ->
                    let! res = x
                    return! loop (res::acc) xs
            }
        loop [] (List.ofSeq asyncs)

然后你可以沿着这些方向做点什么:

escalationEvents
// a collection of asyncs - note that the task won't start until the async is ran
|> List.map (fun x -> 
    async {
        let task = 
            service.PostAction(new Models.Action(x.incident_id, escalationAction, "escalated")) 
        return! Async.AwaitTask task 
    })
// go from a collection of asyncs into an async of a collection
|> Async.sequential
// you don't care about the result, so ignore it
|> Async.Ignore
// now that you have your async, you need to run it in a way that makes sense
// in your context - Async.Start could be another option. 
|> Async.RunSynchronously

这里的好处是,不是将所有内容捆绑到一个循环中,而是将计算分成明确分隔的阶段。它易于跟踪和重构(例如,如果您需要并行处理这些事件,您只需在管道中切换一步)。