2012-03-31 12 views
1

Aus welchen Gründen unterscheiden sich die beiden folgenden Timings so drastisch?Kosten von RunSynchronously

 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 

ich das Objekt Pool nutzen unter

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: Wenn ich die Anzahl der preinitilized bis 10 zu ändern, es ändert nichts. Die Langsamkeit auftritt, bevor die Nachricht im Objektpool empfängt, wenn es sich ansammelt (langsam) ‚cust erwerben‘ auf dem Bildschirm

Antwort

2

Versuchen Sie es in einer Schleife setzen:

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

Ich glaube, Sie gerade erleben die Anfangszeit zum Aufwärmen des Threadpools (der nur zwei standardmäßig zwei Threads pro Sekunde hinzufügt); Sobald es warm ist, sind die Dinge schnell.

+0

interessant. Als ich RunSynchronously anrief, hatte ich den Eindruck, dass es den aktuellen Threadpool einfach wiederverwenden könnte. – nicolas

+0

Die F # asyncs verwenden den ThreadPool. Es ist nur so, dass der .NET ThreadPool klein anfängt und drosselt, wie schnell er mehr Threads zuweist, um zu vermeiden, dass Ressourcen bei einem Ausreißer von Warteschlangen-Items verschwendet werden. – Brian

+1

Danke, dass ich vergessen habe, ein Update zu posten. Du hattest Recht, und ich habe einen SetMinThread hinzugefügt, jetzt ist es in Ordnung. Ich hätte nie gedacht, dass ich so tief gehe, aber es macht Sinn. Thks – nicolas