2012-03-31 47 views
1

以下兩種時間差異如此顯着的原因是什麼?運行成本同步

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

NB對象池:如果我改變的preinitilized到10號,它不會改變任何東西。在屏幕上的對象池接收消息,當它積累(慢)「獲得卡斯特」之前發生 的緩慢

回答

2

嘗試把它在一個循環:

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

我覺得你只是見證預熱線程池的初始時間(默認情況下,它只喜歡每秒添加兩個線程);一旦溫暖,事情就會很快。

+0

有意思。當我調用RunSynchronously時,我的印象是它可以重用當前的線程池。 – nicolas 2012-04-01 11:17:07

+0

F#異步使用ThreadPool。只是.NET ThreadPool從小處開始,並且限制它分配更多線程的速度,以避免在排隊項目活動異常點突發上浪費資源。 – Brian 2012-04-01 22:33:07

+1

謝謝我忘了發佈更新。你是對的,我現在增加了一個setminthread。開始我的項目我從來都不會想到我會深入這個領域,但這確實很有意義。 THKS – nicolas 2012-04-01 22:38:14