Cost of RunSynchronously

2019-08-01 08:35发布

What are the reasons why the two timings below differs so dramatically ?

     let time acquire = 
        let sw = System.Diagnostics.Stopwatch.StartNew()
        sw.Start()
        let tsks = [1 .. 10] |> Seq.map (fun x -> acquire)
        let sec = Async.RunSynchronously(Async.Parallel tsks)
        sw.Stop()
        printfn "Generation time %A ms" sw.Elapsed.TotalMilliseconds  
        sw.Reset()   
        Console.ReadKey() |> ignore

     let custPool = ObjectPool(customerGenerator, 0)
     let acquire  = async { printfn "acquiring cust" ; return! custPool.Get() }
     let acquire2 = async { return Async.RunSynchronously(acquire)}

     time acquire  //   76 ms
     time acquire2 // 5310 ms

I use the object pool below

   type ObjectPool<'a>(generate: unit -> 'a, initialPoolCount) = 
       let initial = List.init initialPoolCount (fun (x) -> generate())
       let agent = Agent.Start(fun inbox ->
           let rec loop(x) = async {
               let! msg = inbox.Receive()
               match msg with
               | Get(reply)   -> let res = match x with  | a :: b     -> reply.Reply(a);b
                                                         | [] as empty-> reply.Reply(generate());empty
                                 printfn "gave one, %A left" (Seq.length res)
                                 return! loop(res)
               | Put(value)   -> printfn "got back one, %A left" ((Seq.length x) + 1 )
                                 return! loop(value :: x) 
               | Clear(reply) -> reply.Reply x 
                                 return! loop(List.empty<'a>) 
           }
           loop(initial))
       /// Clears the object pool, returning all of the data that was in the pool.
       member this.ToListAndClear() = agent.PostAndAsyncReply(Clear)
       /// Puts an item into the pool
       member this.Put        (item) = agent.Post(item)
       /// Gets an item from the pool or if there are none present use the generator
       member this.Get        (item) = agent.PostAndAsyncReply(Get)
   type Customer =  {First : string; Last : string; AccountNumber : int;} override m.ToString() = sprintf "%s %s, Acc: %d" m.First  m.Last m.AccountNumber
   let names,lastnames,rand = ["John"; "Paul"; "George"; "Ringo"], ["Lennon";"McCartney";"Harison";"Starr";],System.Random()
   let randomFromList list=   let length = List.length list
                              let skip = rand.Next(0, length)
                              list |> List.toSeq |> (Seq.skip skip ) |> Seq.head
   let customerGenerator() = { First = names |> randomFromList; 
                             Last= lastnames |> randomFromList; 
                             AccountNumber = rand.Next();}

NB : if I change the number of preinitilized to 10, it does not change anything. The slowness occurs before receiving the message in the object pool, when it accumulates (slowly) 'acquiring cust' on the screen

1条回答
我欲成王,谁敢阻挡
2楼-- · 2019-08-01 09:09

Try putting it in a loop:

for i in 1..5 do 
    time acquire  //   76 ms 
    time acquire2 // 5310 ms 

I think you are just witnessing the initial time to warm up the threadpool (which only likes two add two threads per second by default); once it is warm, things are fast.

查看更多
登录 后发表回答