SORU
6 ŞUBAT 2010, CUMARTESİ


F# çok Ayrık daha hızlı ve süreçleri yumurtlama öldürüyor?

Güncelleme: Bu soru kıyaslama anlamsız. kılan bir hata içeriyor Daha iyi bir kriter F karşılaştırarak çalışacağım# ve Ayrık bir soru sonuçları hakkında temel eşzamanlılık işlevsellik ve sorgulamak.

Bunu eğer X ve F performans özelliklerini anlamaya çalışıyorum#. Eğer x bu eşzamanlılık modeli çok çekici ama ben eğimli F kullanmak buluyorum# birlikte çalışabilirlik nedeniyle. Süre kutudan F# yok bir şey ikram gibi Ayrık değil eşzamanlılık ilkel -- dan ne I-ebilmek söylemek uyumsuz ve MailboxProcessor sadece küçük bir kısmı Ayrık ne yapar Peki ... ben denedim anlamak mümkün F# performans açısından.

Joe Armstrong'un Programlama Ayrık kitapta, işlemler Ayrık çok ucuz olduğu noktaya değindi. (Kabaca) aşağıdaki kodu bu gerçeği göstermek için kullanır:

-module(processes).
-export([max/1]).

%% max(N) 
%%   Create N processes then destroy them
%%   See how much time this takes

max(N) ->
    statistics(runtime),
    statistics(wall_clock),
    L = for(1, N, fun() -> spawn(fun() -> wait() end) end),
    {_, Time1} = statistics(runtime),
    {_, Time2} = statistics(wall_clock),
    lists:foreach(fun(Pid) -> Pid ! die end, L),
    U1 = Time1 * 1000 / N,
    U2 = Time2 * 1000 / N,
    io:format("Process spawn time=~p (~p) microseconds~n",
          [U1, U2]).

wait() ->
    receive
        die -> void
    end.

for(N, N, F) -> [F()];
for(I, N, F) -> [F()|for(I 1, N, F)].

Macbook Pro ve 100 bin süreçleri (**5) yumurtlama öldürme süreçleri başına yaklaşık 8 mikrosaniye sürer. İşlem sayısı biraz daha yükseltebilirim, ama bir milyon şeyler oldukça tutarlı kırmak gibi görünüyor.

Çok az bilerek F# ben bu örnek, zaman uyumsuz ve MailBoxProcessor kullanarak uygulamak için çalıştı. Yanlış olabilir benim girişimi, aşağıdaki gibidir:

#r "System.dll"
open System.Diagnostics

type waitMsg =
    | Die

let wait =
    MailboxProcessor.Start(fun inbox ->
        let rec loop =
            async { let! msg = inbox.Receive()
                    match msg with 
                    | Die -> return() }
        loop)

let max N =
    printfn "Started!"
    let stopwatch = new Stopwatch()
    stopwatch.Start()
    let actors = [for i in 1 .. N do yield wait]
    for actor in actors do
        actor.Post(Die)
    stopwatch.Stop()
    printfn "Process spawn time=%f microseconds." (stopwatch.Elapsed.TotalMilliseconds * 1000.0 / float(N))
    printfn "Done."

F# kullanarak Mono ve 100.000 aktörler/işlemciler başlayan öldürmekten daha hızlı Ayrık'den işlem başına 2 mikrosaniye, yaklaşık 4 kez alır. Daha da önemlisi, belki de, görünürde herhangi bir sorun olmadan işlemler milyonlarca ölçekli olabilir. 1 veya 2 milyon süreçleri başladı hala işlem başına yaklaşık 2 mikrosaniye sürer. 20 milyon işlemciler başlayan hala mümkün olduğunu, ancak işlem başına yaklaşık 6 mikrosaniye için yavaşlatır.

Henüz tam olarak nasıl F anlamak için zaman almış değil# uygulayan uyumsuz ve MailBoxProcessor, ama bu sonuçlar cesaret vericidir. Korkunç bir şekilde yapıyorum bir sorun mu var?

Değilse, bir yerde eğer x büyük olasılıkla daha iyi performans göstereceğini F#? Orada Ayrık bu eşzamanlılık ilkelleri F getirilebilir mi bir nedeni# bir kütüphane ile?

EDİT: yukarıdaki rakamlar yanlış, Brian işaret hatası nedeniyle. Ben bunu düzeltmek zaman tüm soru güncellenir.

CEVAP
6 ŞUBAT 2010, CUMARTESİ


Orijinal kodu, sadece bir MailboxProcessor başladı. wait() fonksiyon yield Her ile arayın. Bunları da spin yukarı ya da zamanlama bilgileri geçersiz kılar ve bence bu mesajları almak; benim kod aşağıda görmek için bekliyor.

Bu, bazı başarı var; kutudan hakkında 25bizi her 100,000 yapabileceğimi söyledi. Sonra çok daha fazla, bence muhtemelen kavga ayırıcısı/GC gibi bir şey, ama ben mümkün yapmak için bir milyon dolar da (yaklaşık 27us her, ama bu noktada kullanmış gibi 1.5 G bellek).

Temel olarak her 'zaman uyumsuz asma bir posta kutusu bir çizgi gibi bekliyorum . ne zaman devlet ('

let! msg = inbox.Receive()

olur bloke ederken bazı bayt sayısı. Bu konuları daha çok, çok, çok daha fazla asyncs olabilir, bu yüzden bu bir iş parçacığı genellikle bellek ya da daha fazla bir megabayt gibi alır.

Tamam, burada ben kullanıyorum kod. 10 gibi küçük bir sayı kullanmak hata AYIKLAMA (printf çıkışları aralanmış olabilir, ama fikir alırsınız) istenen program mantığı sağlamak için tanımlayabilirsiniz.

open System.Diagnostics 

let MAX = 100000

type waitMsg = 
    | Die 

let mutable countDown = MAX
let mre = new System.Threading.ManualResetEvent(false)

let wait(i) = 
    MailboxProcessor.Start(fun inbox -> 
        let rec loop = 
            async { 
#if DEBUG
                printfn "I am mbox #%d" i
#endif                
                if System.Threading.Interlocked.Decrement(&countDown) = 0 then
                    mre.Set() |> ignore
                let! msg = inbox.Receive() 
                match msg with  
                | Die -> 
#if DEBUG
                    printfn "mbox #%d died" i
#endif                
                    if System.Threading.Interlocked.Decrement(&countDown) = 0 then
                        mre.Set() |> ignore
                    return() } 
        loop) 

let max N = 
    printfn "Started!" 
    let stopwatch = new Stopwatch() 
    stopwatch.Start() 
    let actors = [for i in 1 .. N do yield wait(i)] 
    mre.WaitOne() |> ignore // ensure they have all spun up
    mre.Reset() |> ignore
    countDown <- MAX
    for actor in actors do 
        actor.Post(Die) 
    mre.WaitOne() |> ignore // ensure they have all got the message
    stopwatch.Stop() 
    printfn "Process spawn time=%f microseconds." (stopwatch.Elapsed.TotalMilliseconds * 1000.0 / float(N)) 
    printfn "Done." 

max MAX

Tüm bu dedi, bilmiyorum eğer X, ve ben düşündüm derinden duyup bir şekilde aşağı trim F# artık (gerçi çok deyimsel olarak).

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • boogie2988

    boogie2988

    6 NİSAN 2006
  • george sarintzotis

    george sarin

    2 Aralık 2007
  • Ricardo Cerqueira

    Ricardo Cerq

    28 Mayıs 2008