RunSynchronously的成本

时间:2012-03-31 12:43:47

标签: multithreading asynchronous f# threadpool

下面两个时间差异如此显着的原因是什么?

     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

我使用下面的对象池

   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();}

注意:如果我将preinitilized的数量改为10,它不会改变任何东西。 在对象池中接收消息之前,当它在屏幕上累积(缓慢)“获取cust”时,会发生缓慢

1 个答案:

答案 0 :(得分:2)

尝试将其置于循环中:

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

我认为你只是看到了预热线程池的初始时间(默认情况下,它只需要每秒添加两个线程);一旦它变暖,事情就会很快。