您的評論「太多的功能爲實時計算可能成爲重」,使這個有趣的。基準測試和分析是至關重要的,因爲您不想爲了性能而編寫大量難以維護的代碼,只是發現它並不是應用程序中性能至關重要的部分!或者,更糟的是,發現你的性能優化會讓你的特定工作負載變得更糟。
性能最佳的實現將取決於您的具體情況(路徑有多長?系統上有多少個內核?)但我認爲混合使用命令式和功能性方法可能會給您帶來最糟糕的兩個世界。如果你不小心,你可能會失去可讀性和性能!
我會稍微修改missingfaktor's answer以使您從parallel collections獲得性能提升。簡單地添加.par
可以爲您提供巨大的性能提升,這一事實證明了堅持功能性編程的力量!
def distancePar(wps: collection.GenSeq[Waypoint]): Double = {
val parwps = wps.par
parwps.zip(parwps drop 1).map(Function.tupled(distance)).sum
}
我的猜測是,這將工作最好的,如果你有幾個核心的問題拋出,並wps
往往是有點長。如果你的內核很少或者路徑很短,那麼並行性可能會比它所能幫助的更多。
另一個極端將是一個完全必要的解決方案。只要你避免共享的可變狀態,寫個人的,性能關鍵的函數的命令性實現通常是可以接受的。但是一旦你習慣了FP,你會發現這種功能更難以編寫和維護。並行並不容易。
def distanceImp(wps: collection.GenSeq[Waypoint]): Double = {
if (wps.size <= 1) {
0.0
} else {
var r = 0.0
var here = wps.head
var remaining = wps.tail
while (!remaining.isEmpty) {
r += distance(here, remaining.head)
here = remaining.head
remaining = remaining.tail
}
r
}
}
最後,如果你正在尋找FP和命令之間的中間地帶,你可能會嘗試遞歸。我沒有介紹它,但我的猜測是,這將大致相當於性能方面的必要解決方案。
def distanceRec(wps: collection.GenSeq[Waypoint]): Double = {
@annotation.tailrec
def helper(acc: Double, here: Waypoint, remaining: collection.GenSeq[Waypoint]): Double =
if (remaining.isEmpty)
acc
else
helper(acc + distance(here, remaining.head), remaining.head, remaining.tail)
if (wps.size <= 1)
0.0
else
helper(0.0, wps.head, wps.tail)
}
回覆:您的更新沒有任何必要,它只是功能性的,但可能比'zipped.map'解決方案更昂貴。 – missingfaktor 2012-02-17 10:18:58
注意'wps(i)',它可能對某些序列具有'O(n)'複雜性,最終會以'O(n^2)'最終的複雜性結束。 – 2012-02-17 10:21:59
你是對的。選擇序列類型時,我應該更加小心。在討論這個問題時,我已經切換到了可變緩衝區類型,但是我將不得不做一些可能的序列類型和各種建議解決方案的基準。那將是一次很好的體驗! – noncom 2012-02-17 10:26:20