I've been trying to learn how to use asynchronous message based methods. Below is a simplified version of what I was trying to do. I'm trying to use a finite state machine within a MailboxProcessor within an object. Overall it appears that the logic can be much more straightforward compared to using event based methods. I have an issue though when I try to use Async.Parallel. In the code following the printfn "Eval %i" v statement is getting evaluated twice for i1 & i2 instead of just one time for each. Which leads me to believe that I am not properly using Async.Parallel. Is there an alternative method that should be used within an asynchronous workflow?
type Input(v) =
let agent =
MailboxProcessor.Start(fun inbox ->
let rec loop() =
async {
let! (msg : AsyncReplyChannel<int>) = inbox.Receive()
printfn "Eval %i" v
msg.Reply(v)
return! loop()
}
loop())
member this.Eval = agent.PostAndAsyncReply(fun r -> r)
let i1 = Input(1)
let i2 = Input(2)
async {
let! nodeValues = [ i1; i2 ]
|> Seq.map(fun n -> n.Eval)
|> Async.Parallel
return nodeValues
}
|> Async.RunSynchronously
1 Answer 1
This is a bug in F# 3.0. Async.Parallel calls Seq.toArray twice. Run your code under F# 3.1 and it will only print once. Here's the fix in the F# source repository.
2 Comments
Async.Parallel method has enough dependencies that it's more than just a minor snippet that I would need if I wanted to use the 3.1 methodology in VS2012. When I'm using Array.map and starting with an array going into the Async.Parallel method is the Seq.toArray call effectively getting ignored then? I guess what I'm asking does using Array.map in F# 3.0 solve the issue or do I need to avoid Async.Parallel in 3.0 altogether? Thanks!Async.parallel should take an array to begin with and not a sequence. It doesn't actually support lazy evaluation and this could lead some users astray.
async { }block.[ i1; i2 ] |> Seq.map (fun n -> n.Eval) |> Async.Parallel |> Async.RunSynchronouslywill work.Evalmethod in this case) in parallel within an async workflow. See link for an larger example.Async.ParallelintoAsync.Ignore |> Async.Start? What do you want to do with the results fromEvalonce they're done?Eval 1andEval 2printed out once with the code above, as would be expected. What's your environment?nodeValuesdefinition tolet! nodeValues = [| i1; i2 |] |> Array.map(fun n -> n.Eval) |> Async.Parallel. Anyone run across different behavior betweenSeq.mapversusArray.mapwithin an async workflow before?