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
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).
Neden sıralanmamış bir dizi daha hızlı...
&; Daha hızlı &;=lt lt?...
Neden Python kodunu daha hızlı bir işl...
Hangisi daha hızlı: while(1) veya(2)?...
Tabanlı uygulamalar Hızlı bir işletim ...