14

F# のリストと配列のパフォーマンスをチェックしていました。コードを考えると:

let list = [ 1.. 100000 ]
for i in 1 .. 100 do ignore ( list|>List.map(fun n -> n))

let array = [| 1.. 100000 |]
for i in 1 .. 100 do ignore ( array|>Array.map(fun n -> n))

私は両方が非常に同じ時間に実行されると思います。実際、配列は 10 倍以上高速であることが判明しました。配列は 28 ミリ秒かかり、リストは 346 ミリ秒かかります! 何故ですか?F# のリストの概念と、たとえばリストに値を追加したり、サブシーケンスを取得したりするのは時間がかかるという事実を理解していますが、このコードではすべての要素を繰り返すだけなので、タイミングは非常に似ていると思いました。

Visual Studio 2012 のリリース モードでのテスト (デバッグ モードでは、配列は約 5 倍高速です)。

4

1 に答える 1

16

主な違いは、配列がメモリの連続ブロックとして割り当てられることです。Array.map関数は入力配列のサイズを認識しており、単一の割り当てを実行して、結果の配列のすべてのメモリを取得できます。一方、List.map関数は、入力配列の各要素に対して 1 つの「コンス セル」を個別に割り当てる必要があります。

関数の違いは特に顕著ですmap。これは、事前割り当ての恩恵を受けることができるためです。ただし、配列は一般に、より大きなデータ セットに対して高速です。フィルタリングを使用するようにコードを変更すると (構築中に配列を再割り当てする必要がある場合)、配列バージョンは ~2x 高速になります。

for i in 1 .. 100 do ignore ( list|>List.filter(fun n -> n%5=1))
for i in 1 .. 100 do ignore ( array|>Array.map(fun n -> n%5=1))

リストを使用すると、他にも利点があります。リストは不変であるため、リストへの参照を安全に共有できます。また、リストを複製して先頭に要素を追加することは非常に効率的ですが (単一セルの割り当て)、配列で同様の操作を行うと非常に遅くなります (配列全体をコピーします)。

于 2013-10-22T14:08:00.800 に答える