2015-12-17 41 views
2

我已經花了上個月左右學習茱莉亞,我印象非常深刻。特別是我正在分析大量的氣候模型輸出,我把這一切都放到了SharedArrays,並且調整並且並行繪製了所有這些。到目前爲止,它非常快速和高效,並且我有相當多的代碼庫。我目前的問題是創建一個可以在兩個共享陣列上執行基本操作的函數。我已經成功地編寫了一個函數,它使用兩個數組以及您想如何處理它們。該代碼是基於圍繞在朱文檔的平行部分的示例,並且使用myrange函數如圖有結合兩個SharedArrays的基本操作

function myrange(q::SharedArray) 
    idx = indexpids(q) 
    #@show (idx) 
    if idx == 0 
     # This worker is not assigned a piece 
     return 1:0, 1:0 
     print("NO WORKERS ASSIGNED") 
    end 
    nchunks = length(procs(q)) 
    splits = [round(Int, s) for s in linspace(0,length(q),nchunks+1)] 
    splits[idx]+1:splits[idx+1] 
end 

function combine_arrays_chunk!(array_1,array_2,output_array,func, length_range); 
    #@show (length_range) 
    for i in length_range 
     output_array[i] = func(array_1[i], array_2[i]); 
     #hardwired example for func = + 
     #output_array[i] = +(array_1[i], array_2[i]); 
    end 
    output_array 
end 

combine_arrays_shared_chunk!(array_1,array_2,output_array,func) = combine_arrays_chunk!(array_1,array_2,output_array,func, myrange(array_1)); 

function combine_arrays_shared(array_1::SharedArray,array_2::SharedArray,func) 
    if size(array_1)!=size(array_2) 
     return print("inputs not of the same size") 
    end 
    output_array=SharedArray(Float64,size(array_1)); 
    @sync begin 
     for p in procs(array_1) 
      @async remotecall_wait(p, combine_arrays_shared_chunk!, array_1,array_2,output_array,func) 
     end 
    end 
    output_array 
end 

作品所以可以做

strain_div = combine_arrays_shared(eps_1,eps_2,+); 
strain_tot = combine_arrays_shared(eps_1,eps_2,hypot); 

與正確的結果的輸出作爲需要的共享陣列。但是......這很慢。將sharedarray作爲一個正常的陣列結合到一個處理器上,計算然後再轉換回sharedarray(對於我的測試用例,每個陣列大約200MB,當我移動到GB時,我估計不會)。我可以硬連線combine_arrays_shared功能只做添加(或其他功能),然後你得到速度增加,但在combine_arrays_shared內傳遞的函數類型,整個事情很慢(比硬連線添加慢10倍)。

我已經看過FastAnonymous.jl包,但我看不出它在這種情況下如何工作。我試過了,失敗了。有任何想法嗎?

我可能只是訴諸編寫不同的combine_arrays_...功能我用的各項基本功能,或具有func參數作爲一個選項,並從combine_arrays_shared中調用不同的功能,但我希望它是更優雅!這也是瞭解更多關於朱莉婭的好方法。

哈利

回答

1

這個問題實際上已經無關SharedArrays,而僅僅是「我怎麼傳遞的功能,作爲論點,並獲得更好的性能?」

FastAnonymous的工作方式---類似於封閉式方法在茱莉亞即將開展工作---就是用call方法創建一個類型。如果您有出於某種原因與FastAnonymous麻煩,你總是可以做手工:

julia> immutable Foo end 

julia> Base.call(f::Foo, x, y) = x*y 
call (generic function with 1036 methods) 

julia> function applyf(f, X) 
      s = zero(eltype(X)) 
      for x in X 
       s += f(x, x) 
      end 
      s 
     end 
applyf (generic function with 1 method) 

julia> X = rand(10^6); 

julia> f = Foo() 
Foo() 

# Run the function once with each type of argument to JIT-compile 
julia> applyf(f, X) 
333375.63216645207 

julia> applyf(*, X) 
333375.63216645207 

# Compile anything used by @time 
julia> @time 1 
    0.000004 seconds (148 allocations: 10.151 KB) 
1 

# Now let's benchmark 
julia> @time applyf(f, X) 
    0.002860 seconds (5 allocations: 176 bytes) 
333433.439233112 

julia> @time applyf(*, X) 
    0.142411 seconds (4.00 M allocations: 61.035 MB, 19.24% gc time) 
333433.439233112 

注意速度,大大減少的內存消耗大的增加。

+0

因此,一個正確的問題的例子!這樣做現在變得更有意義了,所以我可以將類型f賦值給我需要的函數,然後高效地傳遞函數。有沒有一種方法可以在函數內分配這種類型?因此,對於上面的示例,頂部'combine_arrays_shared'將執行賦值,然後該函數被有效地傳遞給'combine_arrays_chunk!'函數?我會放棄它。 –