2012-12-04 14 views
11

Bilgisayar Dili Kıyaslama Oyunu F# entry for Threadring, görünüşte işe yaramaz bir çizgi içermektedir: if false then(). Bu çizgiyi açıkladığımda, program çok daha hızlı çalışır (~ 500s000 giriş için ~ 55 vs) ve aynı sonucu verir. Bu nasıl çalışıyor? Bu hat neden orada? Derleyicinin no-op gibi görünen şeylerle tam olarak ne işi var?Bilgisayar Dili Kıyaslama Oyununun F # Threadring girdisinde "false then()" ifadesinin etkisi nedir?

kodu:

let ringLength = 503 

let cells = Array.zeroCreate ringLength 
let threads = Array.zeroCreate ringLength 
let answer = ref -1 

let createWorker i = 
    let next = (i+1)%ringLength 
    async { let value = cells.[i] 
      if false then() 
      match value with 
      | 0 -> answer := i+1 
      | _ -> 
       cells.[next] <- value - 1 
       return! threads.[next] } 

[<EntryPoint>] 
let main args = 
    cells.[0] <- if args.Length>0 then int args.[0] else 50000000 
    for i in 0..ringLength-1 do 
     threads.[i]<-createWorker i 

    let result = Async.StartImmediate(threads.[0]) 
    printfn "%d" !answer 
    0 

cevap

7

hesaplama ifade asenkron akışı biraz farklı tercüme sonra if false then() içeriyorsa. Çizgiyle async.Combine kullanır. if döngü tarafından yapılan (potansiyel olarak) asenkron hesaplama aşağıdaki kod ile kombine edilmesi gerekmektedir, çünkü

async.Delay(fun() -> 
    value = cells.[i] 
    async.Combine 
    (async.Return(if false then()) 
     async.Delay(fun() -> 
     match value with (...)))) 

için Combine ekler: gibi biraz basitleştirilmiş kodu bakar. Eğer if silerseniz Şimdi, böyle bir şey olsun:

async.Delay(fun() -> 
    value = cells.[i] 
    match value with (...)))) 

fark artık çok daha fazla iş Delay geçirilen işlevinde hemen yapılır olmasıdır.

DÜZENLEME: Ben kodu Async.StartImmediate yerine Async.Start kullanır, ancak bu durumda olması görünmüyor çünkü bu bir fark neden düşündük. Aslında, kodun neden asenkron iş akışlarını kullandığını anlamıyorum ...

EDIT II.: Ben Mono hakkında tamamen emin değilim, ama kesinlikle F # interaktif içinde çoğalır - orada, Combine ile sürüm yaklaşık 4 kat daha yavaş (hangi ben, hangi fonksiyon tahsisi yükü nedeniyle beklediğim).

9

Bu kodu özgün olarak yazdım. Çizgiyi eklediğimin tam nedenini hatırlamıyorum, ama tahmin edeyim ki, onsuz, optimizatör, kıyaslama oyununun ruhu dışında olduğunu düşündüğüm bir şeyi yapardı. En başta async kullanmanın sebebi, bir sonraki async'e (bu, C# mono'dan çok daha iyi performans göstermesini sağlayan) kuyruk arama devamı sağlamaktır. - Jomo

+0

+1 yetkili bir yanıt için (olduğu gibi), ama merak ediyorum neden bir _ benchmark_ performansının nedenini cezalandırmak istersiniz ... – ildjarn

+2

Tekrar düşünmek istediğime inanıyorum. Aynı donanım ipliği üzerinde devam eden paylaşımları paylaşırken, bağımsız meşru yürütme bağlamları olan uyumsuzlukları göstermek (Go goroutines'e benzer bir kullanım modeli yapmak). Hatsız olarak, F # her şeyi etkin bir şekilde bir döngü içine alırdı. Bu bir kıyaslama için canlandırıcı olacak, ancak kodu gerçek bir şey için kullanmaya çalıştığınız anda, performans 20x oranında düşecektir. –