元 C プログラマーで現在の Erlang ハッカーとして、1 つの疑問が浮かびました。
Erlang データ構造のメモリ スコープを見積もるにはどうすればよいですか?
C に 1k の整数の配列があり、これのメモリ需要を見積もるのは簡単です。配列のサイズに整数のサイズを掛けると、1k の 32 ビット整数は 4kb またはメモリを占有し、一定量のポインタとインデックス。
しかし、erlang では、メモリ使用量の推定はやや複雑です。erlangs 配列構造のエントリはどのくらいのメモリを占有しますか?動的にサイズ変更される整数のサイズを推定するにはどうすればよいですか?
配列内の整数のスキャンは erlang ではかなり遅いことに気付きました。約 1M の整数の配列をスキャンするには、erlang ではほぼ 1 秒かかりますが、単純な C コードでは約 2 ミリ秒で実行されます。これはおそらく次の理由によるものです。データ構造が占有するメモリの量。
私がこれを尋ねているのは、私がスピードマニアだからではなく、少なくとも私の経験では、メモリの見積もりがソフトウェアのスケーラビリティを判断する良い方法だったからです。
私のテストコード:
最初に C コード:
#include <cstdio>
#include <cstdlib>
#include <time.h>
#include <queue>
#include <iostream>
class DynamicArray{
protected:
int* array;
unsigned int size;
unsigned int max_size;
public:
DynamicArray() {
array = new int[1];
size = 0;
max_size = 1;
}
~DynamicArray() {
delete[] array;
}
void insert(int value) {
if (size == max_size) {
int* old_array = array;
array = new int[size * 2];
memcpy ( array, old_array, sizeof(int)*size );
for(int i = 0; i != size; i++)
array[i] = old_array[i];
max_size *= 2;
delete[] old_array;
}
array[size] = value;
size ++;
}
inline int read(unsigned idx) const {
return array[idx];
}
void print_array() {
for(int i = 0; i != size; i++)
printf("%d ", array[i]);
printf("\n ");
}
int size_of() const {
return max_size * sizeof(int);
}
};
void test_array(int test) {
printf(" %d ", test);
clock_t t1,t2;
t1=clock();
DynamicArray arr;
for(int i = 0; i != test; i++) {
//arr.print_array();
arr.insert(i);
}
int val = 0;
for(int i = 0; i != test; i++)
val += arr.read(i);
printf(" size %g MB ", (arr.size_of()/(1024*1024.0)));
t2=clock();
float diff ((float)t2-(float)t1);
std::cout<<diff/1000<< " ms" ;
printf(" %d \n", val == ((1 + test)*test)/2);
}
int main(int argc, char** argv) {
int size = atoi(argv[1]);
printf(" -- STARTING --\n");
test_array(size);
return 0;
}
そしてアーランコード:
-module(test).
-export([go/1]).
construct_list(Arr, Idx, Idx) ->
Arr;
construct_list(Arr, Idx, Max) ->
construct_list(array:set(Idx, Idx, Arr), Idx + 1, Max).
sum_list(_Arr, Idx, Idx, Sum) ->
Sum;
sum_list(Arr, Idx, Max, Sum) ->
sum_list(Arr, Idx + 1, Max, array:get(Idx, Arr) + Sum ).
go(Size) ->
A0 = array:new(Size),
A1 = construct_list(A0, 0, Size),
sum_list(A1, 0, Size, 0).
C コードのタイミング:
bash-3.2$ g++ -O3 test.cc -o test
bash-3.2$ ./test 1000000
-- STARTING --
1000000 size 4 MB 5.511 ms 0
そしてアーランコード:
1> f(Time), {Time, _} =timer:tc(test, go, [1000000]), Time/1000.0.
2189.418