F#, MailboxProcessor and Async running slow? -


background.

i trying figure out mailboxprocessor. idea use kind of state machine , pass arguments around between states , quit. parts going have async communication made sleep there. it's console application, making post nothing because main thread quits , kills behind it. making postandreply in main. also, have tried without

let sleepworkflow  = async 

, doesn't make difference.

questions.

(i doing wrong)

  1. go24 not async. changing runsynchronously startimmediate makes no visible difference. end should somewhere below getme instead. @ same time done printed after fetch. isn't control supposed t returned main thread on sleep?

    go24, wait go24 1, end fetch 1 done getme ...

  2. run time terrible slow. without delay in fetch it's 10s (stopwatch). thought f# threads lightweight , should use threadpool. according debugger takes appr 1s create every , looks real threads.

also, changing [1..100] "pause" program 100s, according processexplorer 100 threads created during time , printed. prefer fewer threads , slow increase.

code.

program.fs

[<entrypoint>] let main argv =       let = mailbox.messagebasedcounter.dogo24 1     let = mailbox.messagebasedcounter.dofetch 1     let b = mailbox.messagebasedcounter.getme      let task  = async {         //mailbox.messagebasedcounter.dogo24 1         let = mailbox.messagebasedcounter.dofetch         return         }      let stopwatch = system.diagnostics.stopwatch.startnew()      let x =          [1..10]             |> seq.map task             |> async.parallel             |> async.runsynchronously      stopwatch.stop()     printfn "%f" stopwatch.elapsed.totalmilliseconds      printfn "a: %a"     printfn "b: %a" b      printfn "x: %a" x     0 // return integer exit code 

mailbox.fs

module mailbox  #nowarn "40"  type parsermsg =     | go24 of int     | done     | fetch of int * asyncreplychannel<string>     | getme of asyncreplychannel<string>   type messagebasedcounter () =       /// create agent     static let agent = mailboxprocessor.start(fun inbox ->           // message processing function         let rec messageloop() = async{             let! msg = inbox.receive()              match msg              | go24 n ->                 let sleepworkflow  = async{                     printfn "go24, wait"                     do! async.sleep 4000                      messagebasedcounter.dodone() // post done.                     printfn "go24 %d, end" n                     return! messageloop()                 }                  async.runsynchronously sleepworkflow             | fetch (i, repl) ->                 let sync = async{                     printfn "fetch %d"                     do! async.sleep 1000                     repl.reply( "reply fetch " + i.tostring() ) // reply caller                      return! messageloop()                 }                 async.runsynchronously sync              | getme (repl) ->                 let sync = async{                     printfn "getme"                     repl.reply( "getme" ) // reply caller                      return! messageloop()                 }                 async.runsynchronously sync             | done ->                  let sync = async{                     printfn "done"                     return! messageloop()                 }                 async.runsynchronously sync              }          // start loop          messageloop()         )      // public interface hide implementation     static member dodone () = agent.post( done )     static member dogo24 (i:int) = agent.post( go24(i) )     static member dofetch (i:int) = agent.postandreply( fun reply -> fetch(i, reply) )     static member getme = agent.postandreply( getme ) 

i'm not sure main problem, nested asyncs , async.runsynchrously in agent code suspicious.

you not need create nested async - can call asynchronous operations in body of match clauses directly:

// message processing function let rec messageloop() = async{   let! msg = inbox.receive()    match msg    | go24 n ->       printfn "go24, wait"       do! async.sleep 4000        messagebasedcounter.dodone()       printfn "go24 %d, end" n       return! messageloop()    | fetch (i, repl) ->       (...) 

aside that, important understand agent has 1 instance of body computation running. so, if block body of agent, other operations queued.

if want start task (like synchronous operations) in background , resume agent immediately, can use async.start inside body (but sure call main loop recursively in main part of body):

  | go24 n ->       // create work item run in background       let work = async {         printfn "go24, wait"         do! async.sleep 4000          messagebasedcounter.dodone()         printfn "go24 %d, end" n }       // queue work in thread pool processed       async.start(work)       // continue message loop, waiting other messages       return! messageloop() 

Comments

Popular posts from this blog

javascript - AngularJS custom datepicker directive -

javascript - jQuery date picker - Disable dates after the selection from the first date picker -