ジュリアへの運動の渦を計算してプロットする単純なプログラムを適合させて言語をテストしました。また、特別な理由なしにPythonでも記述しました。
(免責事項:1.読んだスタックオーバーフローのすべてのパフォーマンス比較は、包括的でない/正しくない/適切に記述されている/関連していないなどの理由で非難されます。私はジュリアをより速くする方法を知りたいだけです。2. pythonはCythonなどで最適化、実装できることを知っています。これはこのディスカッションの一部ではありませんが、参照用ですJuliaとPythonの同等の関数の例)
コードとパフォーマンスの結果を見ることができます 要点 。
JuliaのパフォーマンスはFortranよりも大幅に遅くなります。計算自体の実行にかかる時間は(50000タイムステップ)です。
Fortran: 0.051s
Julia: 2.256s
Python: 30.846s
ジュリアはFortranよりもはるかに遅い(約44倍遅い)、ギャップは狭くなりますが、タイムステップが10倍に増えても重要です(0.50s vs 15.24s
)。
これらの結果は Juliaホームページ に表示される結果とは大きく異なります。何が悪いのですか?ジュリアを大幅に速く修正できますか?
私は Julia Performance Tips ページと、Juliaホームページの比較の背後にあるコードをざっと読みましたが、修正すべき点は何もありません。
また興味深いことに、JuliaはPyPlot(5secs
ish !!)およびPythonよりもテキストファイルを読み取るのにかなり時間がかかります。これらを改善するために何かできるでしょうか?
上記の時間は、JuliaとPythonの読み込み時間を示していないことに注意してください。これは、計算AFAIKにかかった実際の時間です-コードを参照してください。 Fortranの場合はそれがすべてです。速度の比較を可能にするために、おおよそ、プロットはオフになっています。
コンピューター:Intel i7-3770、16GB ram、SSD HD、OS:Ubuntu 13.10 64ビット。Fortran:gfortran、GNU Fortran(Ubuntu/Linaro 4.8.1-10ubuntu9)4.8.1、Julia :バージョン0.3.0-prerelease + 396(2013-12-12 00:18 UTC)、コミットc5364db *(0日経過したマスター)、x86_64-linux-gnu、Python:2.7.5+
Ivarneのアドバイスに基づいて、Juliaスクリプト(上記のGistで更新)を書き直しました。関数内でのうなり声の作業をカプセル化し、すべての型を宣言し、必要に応じて行列のさまざまな要素をさまざまな配列に分割します。 (私はFloat32を試して、それが役に立ったかどうかを確認したので、かなりの数の場所にFloat64を含めましたが、ほとんどの場合はそうではありませんでした)。
結果は次のとおりです。
50,000
タイムステップ:
Fortran: 0.051s (entire programme)
Julia: raw calc.: 0.201s, calc. and return (?): 0.758s, total exec.: 6.947s
500,000
タイムステップ:
Fortran: 0.495s (entire programme)
Julia: raw calc.: 1.547s, calc. and return (?): 2.094s, total exec.: 8.521s
結論として:
ジュリアをかなりスピードアップできます。
パフォーマンスの測定方法によっては、ジュリアの見かけ上の速度に大きな影響を与える可能性があります。
Juliaプロジェクトをしばらくフォローしてきましたが、関連があると思われるコードへのコメントがあります。
PyPlot(およびその他のパッケージ)の読み込み時間は既知の問題です。これは、Juliaコードの解析とマシンコードへのコンパイルに時間がかかるためです。このプロセスにキャッシュを持たせることで、このプロセスが瞬時になるようにすることはできますが、まだ完了していません。現在、ベースライブラリはコンパイルされた状態でキャッシュされているため、インフラストラクチャのほとんどは現在マスターブランチにあります。
[〜#〜] added [〜#〜]:分離された関数でテストを実行しようとすると、これらの結果が得られました。これを見てください 要旨
解析:
elapsed time: 0.334042578 seconds (11797548 bytes allocated)
そして、メインテストループの連続するルーンをツリーします。
elapsed time: 0.62999287 seconds (195210884 bytes allocated)
elapsed time: 0.39398753 seconds (184735016 bytes allocated)
elapsed time: 0.392036875 seconds (184735016 bytes allocated)
コンパイルされたコードが再度使用されたため、最初の実行後にタイミングがどのように改善されたかに注目してください。
Update 2改善されたメモリ処理(割り当てがコピーされないため、配列の再利用を確実にする)により、タイミングを0.2秒に短縮しました(私のマシン上) )。新しい配列の割り当てを回避するためにできることは間違いなくありますが、それから少しトリッキーになります。
この行はあなたが思っていることをしていません:
vx_old = vx
しかし、これはあなたが望むことをします:
copy!(vx_old, vx)
1つのループをベクトル化解除します。
x += 0.5*(vx + vx_old)*delta_t
y += 0.5*(vy + vy_old)*delta_t
に:
for i = 1:nvortex
x[i] += 0.5*(vx[i] + vx_old[i])*delta_t
y[i] += 0.5*(vy[i] + vy_old[i])*delta_t
end
@ivarneはこれをカバーしていますが、もう少し注意が必要です。
Julia> @time x=[1:10000];
elapsed time: 1.544e-5 seconds (80120 bytes allocated)
Julia> @time y = x[1:10000];
elapsed time: 2.6857e-5 seconds (80120 bytes allocated)
ワオ。それは多くの時間と記憶です。
Julia> @time z = sub(x,1:10000);
elapsed time: 6.239e-6 seconds (296 bytes allocated)
ずっといい。 [:]
がsub
の機能を実行しないのはなぜですか?知りません。まあ、私はそうします。インデックスz[10]
に移動すると、ジュリアはhrmm、zがxに似ていることを除いて、インデックスが0だけオフセットされるので、z[10]
はx[10+0]
になります。どうぞ。インデックスを大量に作成する場合、少し追加するだけで長期的にはコストがかかります。これを修正するには、ジュリアの宗教に反するポインターのような概念が必要です。
更新 Juliaは[:]
を廃止しました(バージョン0.4.0)
Julia> @time x=[1:10000];
WARNING: [a] concatenation is deprecated; use collect(a) instead
in depwarn at deprecated.jl:73
in oldstyle_vcat_warning at ./abstractarray.jl:29
in vect at abstractarray.jl:32
while loading no file, in expression starting on line 155
0.530051 seconds (180.12 k allocations: 9.429 MB, 5.26% gc time)
Julia> @time x=[1:10000];
WARNING: [a] concatenation is deprecated; use collect(a) instead
in depwarn at deprecated.jl:73
in oldstyle_vcat_warning at ./abstractarray.jl:29
in vect at abstractarray.jl:32
while loading no file, in expression starting on line 155
0.001373 seconds (303 allocations: 714.656 KB)
収集が速い
Julia> @ time x=collect(1:10000);
0.003991 seconds (35 allocations: 80.078 KB)
Julia> @ time x=collect(1:10000);
0.000031 seconds (8 allocations: 78.406 KB)
subArrayに相当
Julia> @time z = sub(x,1:10000);
0.067002 seconds (36.27 k allocations: 1.792 MB)
Julia> @time z = sub(x,1:10000);
0.000016 seconds (7 allocations: 288 bytes)