使用Rust開發(fā)并行隨機梯度下降中遇到的問題
解決方案
1. Futures
2. Nalgebra
3. Tokio
其中Tokio負責異步IO,Futures負責并行計算,Nalgebra負責矩陣等數學對象的抽象戒祠。
主要遇到的問題
1. 生命周期以及所有權的問題
當數據結構在閉包和線程之間被使用的時候腹侣,很容易遇到變量的所有權被move的問題婆排,以及變量的ref lifetime不足以保證在某個位置還有效的問題。通過使用Arc和Box等智能指針的形式來進行引用傳遞杂抽,在不同的閉包里clone一個有所有權的指針來解決這個問題近顷,也帶來了一些復雜度生音,并發(fā)的安全性由這些指針的封裝來保證宁否,當然這些封裝里邊也存在大量的unsafe代碼窒升,不過是經過大量測試過的,安全性可以被信賴慕匠。
另外由于有些代碼比如as_slice會造成所有權的轉移饱须,因此代碼很多的精力都放在感受所有權的轉移身上,數據在傳遞給閉包要先clone台谊,傳遞進去的數據要被轉移了蓉媳,接下來就不能使用了,fighting with the compiler.
2. 線程池的成熟程度
Futures包的0.3版本目前只是alpha階段锅铅,只能在nightly的版本中使用酪呻,而nightly的版本極其不穩(wěn)定,經常沒有rls可用盐须,代碼編寫都是個問題玩荠。
后來考慮使用Tokio自己的線程池來替代,基于Futures 0.1版本的包所封裝的線程池實現贼邓,在stable版本中可用阶冈,最終出乎意料的順利
3. Channel 的使用
管道同樣有所有權和運行的問題,因為通過管道發(fā)送數據本身就是一種Future塑径,如果需要在當前線程中運行女坑,只需要block住該future,而在Futures 0.3版本中统舀,沒有好用的api匆骗。
最終使用的是標準庫里邊的mpsc,通過在線程池的某個線程中將結果send出去誉简,在主線程阻塞receive結果并更新參數绰筛。
結論
最終實現的sgd在一萬行數據,每行一萬個feature 的情況下描融,
沒有使用lapack加速铝噩,純粹依賴rust的計算,大概執(zhí)行時間是150秒,比直接在spark集群上還要快同時消耗內存也小很多;
開啟lapack支持骏庸,速度并沒有明顯提升毛甲,也許和mac系統(tǒng)的lapack 優(yōu)化有關,在linux下同樣的性能會好很多
對于feature比較少的情況具被,速度提升更明顯玻募,當只有幾十個feature的時候一萬行數據只需要3秒左右的時間即可收斂到接近最優(yōu)解。