2017-11-23 5 views
1

私は、ハードディスク上の大きなフロートセットのシリアライゼーションを最適化するタスクを持っています。 私の最初のアプローチは、以下があります。大量の浮動小数点数のcentOS上の文字列シリアル化は、チャンクを直列化する4個のpthread-tよりも高速です。 Windowsでstd :: threadsが高速になっています

class StringStreamDataSerializer 
{ 
public: 
void serializeRawData(const vector<float>& data); 
void saveToFileStream(std::fstream& file); 
private: 
stringstream _stringStream; 
}; 

void StringStreamDataSerializer::serializeRawData(const vector<float>& data) 
{ 
for (float currentFloat : data) 
    _stringStream << currentFloat; 
} 

void StringStreamDataSerializer::saveToFileStream(std::fstream& file) 
{ 
file << _stringStream.str().c_str(); 
file.close(); 
} 

私は速く シリアル化を行うために、4つのスレッド間serializatonのタスクを分離したかったです。方法は次のとおりです。

struct st_args 
{ 
const vector<float>* data; 
size_t from; 
size_t to; 
size_t segment; 
} ; 

string outputs[4]; 
std::mutex g_display_mutex; 
void serializeLocal(void *context) 
{ 
struct st_args *readParams = (st_args*)context; 

for (auto i = readParams->from; i < readParams->to; i++) 
{ 
    string currentFloat = std::to_string(readParams->data->at(i)); 

    currentFloat.erase(currentFloat.find_last_not_of('0') + 1, 
    std::string::npos); 
    outputs[readParams->segment] += currentFloat; 
} 
} 

void SImplePThreadedSerializer::serializeRawData(const vector<float>& data) 
{ 
const int N = 4; 
size_t totalFloats = data.size(); 
st_args* seg; 
pthread_t* chunk; 

chunk = (pthread_t *) malloc(N*sizeof(pthread_t)); 
seg = (st_args *) malloc(N*sizeof(st_args)); 

size_t from = 0; 
for(int i = 0; i < N; i++) 
{ 
    seg[i].from = 0; 
    seg[i].data = &data; 
} 

int i = 0; 
for (; i < N - 1; ++i) 
{ 
    seg[i].from = from; 
    seg[i].to = seg[i].from + totalFloats/N; 
    seg[i].segment = i; 

    pthread_create(&chunk[i], NULL, (void *(*)(void *)) serializeLocal, 
(void *) &(seg[i])); 
    from += totalFloats/N; 
} 

seg[i].from = from; 
seg[i].to = totalFloats; 
seg[i].segment = i; 

pthread_create(&chunk[i], NULL, (void *(*)(void *)) serializeLocal, (void *) 
&(seg[i])); 

size_t totalBuffered = 0; 
for (int k = 0; k < N; k++) 
{ 
    pthread_join(chunk[k], NULL); 
    totalBuffered += outputs[k].size(); 
} 
str.reserve(totalBuffered); 
for (int k = 0; k < N; k++) 
{ 
    str+= outputs[k]; 
} 

free(chunk); 
free(seg); 
} 

Linuxでは、文字列ストリームが4つのスレッドより速いことが判明しました。 Windowsでは、Windows上で提示された方法(std :: threadを使用)で最適化をアーカイブしていますが、Linuxでは逆の結果が得られます。どのような説明が有用であり、評価されるのか?ハードディスク上の10000000台の山車の *シリアル* 0.55秒で、ファイル内 StringStreamDataSerializerのフラッシュデータ:ここ

はCentOSの上の結果があります。 StringStreamDataSerializer 3.28秒で終了しました。 SImplePThreadedSerializerは、0.46秒でファイル内のデータをフラッシュします。 SImplePThreadedSerializer 6.96秒で終了しました。

Windows上

、マルチスレッドのシリアル化が4つのstd ::スレッドで実行され、彼らが実際にシリアル化を最適化する:

static void serializeChunk(string& output, const vector<float>& data, size_t 
from, size_t to) 
{ 
for (auto i = from; i < to; i++) 
{ 
    string currentFloat = std::to_string(data[i]); 

    //fuckin trim the zeroes at the end 
    currentFloat.erase(currentFloat.find_last_not_of('0') + 1, 
std::string::npos); 
    output += currentFloat; 
} 
} 

void SimpleMultiThreadedSerializer::serializeRawData(const vector<float>& 
data) 
{ 

const int N = 4; 
thread t[N]; // say, 4 CPUs. 
string outputs[N]; 
size_t totalFloats = data.size(); 

size_t from = 0; 

int i = 0; 
for (; i < N - 1; ++i) 
{ 
    t[i] = thread(serializeChunk, std::ref(outputs[i]), data, from, from + 
totalFloats/N); 
    from += totalFloats/N; 
} 
t[i] = thread(serializeChunk, std::ref(outputs[i]), data, from, 
totalFloats); 

for (i = 0; i < N; ++i) 
    t[i].join(); 

size_t totalBuffered = 0; 
for (int i = 0; i < N; ++i) 
    totalBuffered += outputs[i].size(); 

str.reserve(totalBuffered); 
for (int i = 0; i < N; ++i) 
    str += outputs[i]; 
} 

と結果:ハードディスク上の1000000台の山車の *シリアル* StringStreamDataSerializerは、0.116秒でファイル内のデータをフラッシュします。 StringStreamDataSerializer 10.236秒で終了しました。

SimpleMultiThreadedSerializerは、0.105秒でファイル内のデータをフラッシュします。 SimpleMultiThreadedSerializer 3.01秒で終了しました。

答えて

0

バイナリ浮動小数点と小数出力の変換は非常に高価です。パフォーマンスが懸念される場合は、バイナリでデータをシリアル化する必要があります(おそらく、エンディアン変換の後に、少なくともIEEE 754システム間の相互運用性を確保する必要があります)。

GNU/Linuxパフォーマンスでの不良スレッドに関しては、これはknown performance issue regarding locale object handlingのようなものです。マルチスレッドモードでは、stringstreamは現在、ロケール処理のためにプロセス全体にわたり頻繁に競合する参照カウンタを使用しています。

+0

返信いただきありがとうございます!私はその問題を理解していると思う。私は、ftoaメソッドを実装して使用しようとします。ftoaメソッドはロケールオブジェクトを取得し、ロックするか、まったく使用しません。 – GeorgiF

関連する問題