2015-10-31 23 views
13

幾個月前,我開始使用茱莉亞,在幾周聽到人們讚揚它的各種特徵後決定試一試。我學到的東西越多,我越喜歡它的風格,融合了以高級語言表達概念的便捷性,並注重速度和可用性。我實現了一個我也用Julia的C++和R編寫的模型,發現Julia版本的運行速度比R版本快得多,但仍比C++稍慢。即使如此,Julia的代碼也比其他兩種語言更清晰。這是值得的,特別是當我推廣這個模型時,爲擴大Julia代碼範圍所做的工作量要遠遠低於其他語言中可能的工作量。我用Julia吧?

最近,我一直專注於讓我的Julia代碼跑得更快,因爲我需要運行這個模型數萬億次。在這樣做時,我一直以@code_warntype,@time,@profileProfileViewtrack-allocation標誌爲指導。大。這個工具箱並不像其他語言的剖析工具那麼好,但它仍然指出了很多瓶頸。

我發現我在我的代碼中正好具有我喜歡的Julia的高級表達能力,當我重寫表達式以避免不必要的分配時,我失去了這種表達能力。作爲一個簡單的例子,我最近改變的代碼行,超過清單讀

sum([x*y for x in some_list, y in similar_list]) 

到一個循環,進行迭代,並且增加了一個狀態變量。不是火箭科學,我明白爲什麼不分配數組要快一點。其實這是一個很多雖然更快。所以我做了類似的事情,避免使用Dicts或者「感覺」適合這個問題的複合類型,但是我可以手動跟蹤臨時平行數組中的索引,這是我憎惡的編碼風格,但顯然運行當我重複創建和短暫使用小型數據結構的許多次的特定操作時,速度更快。

總的來說,這在很大程度上是好的,因爲我已經將編寫簡短方法的指令放在心上,所以構成我自己較短方法行爲的更高級方法不需要「擔心」更短的方法工作;較短的可以笨重地閱讀,而不會讓我的程序的核心難以閱讀。

但這讓我想知道我是否「失去了一些東西」。如果語言的全部內容(對於我來說是一個非理論相關的最終用戶)部分是爲了將速度與易於開發/思考/閱讀/維護等相結合,即成爲可寫和可用的技術計算語言,那麼這並不意味着我不應該花費時間考慮最快的方式來合併一堆數字,不應該重寫「容易閱讀」或優雅的代碼,利用映射,過濾器和高級函數的概念轉化爲「笨重的」代碼,這些代碼重新發明輪子來表達這些事情,就低層次跟蹤數組索引而言? (我的某些部分期望一個語言的設計背後有如此多的智能,足夠聰明地「弄清楚」,當我寫sum([x * y])時,實際上並不需要分配一個新數組,我只是懶得找出合適的詞來告訴語言,除了通過手動「告訴」整個循環業務之外,我甚至想過編寫@macros將一些快速表示的代碼「轉換」爲長但更快的loopy表達式,但我認爲如果我基本上試圖擴展編譯器的功能來解決相當直接的問題,這就是我寫這個問題的原因,我必須考慮這個問題。)

也許答案是:「如果你想要真正的高性能代碼,無論如何你都要付出代價。「或者換句話說,快速代碼與令人討厭的不愉快的閱讀循環,數組,跟蹤索引等是快速可讀性權衡空間的有效前沿。如果是這樣,這是完全有效的,因此我不會說我我只是想知道這種編程風格是否真的處於邊界,或者我的經驗是什麼,因爲我的語言不能很好地編程(通過類比,請參閱問題What is your most productive shortcut with Vim?,其中接受的和優秀的答案基本上是OP沒有「得到」它)。我懷疑,即使我已經成功地讓語言做了我想要的東西,那我只是不「獲得」某些東西,但我沒有很好的理解,因爲我擔心我沒有得到的東西對我來說是一個未知的未知數

TL; DR:I爲了獲得更快的性能,我花費了大量時間將我的高級函數調用「分解」爲它們的基本實現(以循環和數組方式),或者表明我沒有想到關於正確編程/使用該語言?

回答

8

我覺得這個話題是密切與已經在朱莉婭用戶組會討論一行Does Julia really solve the two-language problem?,我想從討論到這裏舉一個段落:

@Stefan斯基:

每種 語言都有不同風格和級別的書寫代碼。有高度抽象的C++和低級別的指針追逐C++,它基本上是C.即使在C中,也有 void *風格的編程,它在沒有安全性的情況下有效地動態輸入 。鑑於這個事實,我不確定解決這兩個 語言問題將從這個角度看這個職位是 冒充。強制執行只有一種編程風格對我來說聽起來像是一個問題 ,而不是解決方案。相反,我認爲Julia的 最大的優勢之一就是它能夠適應範圍很廣的 編程風格和級別。

在朱莉婭編程我自己的經驗,表明它可以填補一個現代的編程語言,這會帶來高層次的功能,如並行處理,插座的服務器和...的空白框中的科學家,工程師的手,所有計算大師和實用程序員都希望以高效,可維護和可讀的方式完成他們的工作,並使用編程語言All-in-one
在我看來,你正以正確的方式使用Julia,與其他語言一樣,Julia代表不同的編程風格,你可以優化速度瓶頸,並保持其他部分的可讀性。你也可以使用像Devectorize.jl這樣的工具來避免重寫問題。

+1

好的我已經閱讀了幾次這個討論,我認爲你的總結非常明智。簡短的答案似乎是「你寫出高層次的東西,用同樣的語言寫下低層次的東西是Julia的巨大好處之一。」這讓我覺得很好。 – Philip

+1

順便說一句,是的,Devectorize.jl正在做我正在考慮爲我的特定情況編寫宏時的想法。它的性能基準使我認爲,對於許多目的而言,僅僅將例程優化爲特定情況值得努力,但我會密切關注其發展。 – Philip

6

這是一個很難回答令人滿意的問題。因此,我會盡量做出短暫的貢獻,希望不同意見的「鍋」可能足夠好。因此,這裏有3個觀點在我腦海中會目前:

  1. 一種編程語言,可以比作動量的對象。用戶羣是它的羣衆和他們的風格對它施加的力量。最初的用戶/開發者可以在某個方向上拉語言,因爲它的質量仍然很低。即使非常受歡迎(例如C/C++),語言仍然可以發展,但它很難。朱莉婭的未來仍然是不成文的,但它的承諾正處於創作者和早期用戶的初始方向。

  2. 優化是最好的延遲,直到正確性得到充分測試。 「不成熟的優化是萬惡之源」(D. Knuth)。再一次記住這一點從未感到痛苦。因此,保持代碼的可讀性和正確性會更好,直到優化階段可能會混淆代碼的有界區域。

  3. 表達式sum([x*y ...])可能要求編譯器太聰明瞭,最好簡單地定義一個sumprod(x,y)。這將允許sumprod利用Julia的通用功能多調度框架並針對xy保持優化,並且可能以後針對特定類型的xy進行更優化。

就是這樣,現在。意見很多。所以讓討論繼續下去。

+0

謝謝 - 我認爲你在#3的觀點特別貼切。 – Philip

1

你能寫一個類來爲你抽象這些概念嗎(即FastDict或FastList或其他)?然後你將擁有相同的可讀性(如果再多一點黑盒子),同時具有高性能代碼。

+0

有效的是,除了方法[不是類,Julia稱「類型」只是「自己」的數據類型,而不是方法],通過編寫更高層次的方法來完成這個苦差事的低級方法。我只關心我正在重塑車輪的可能性。 – Philip