まず、標準的なXML処理ライブラリを使用するのはどうですか?
次に、あなた自身をロールすることを決めたなら、Win32 APIには直接行ってはいけません。少なくとも、生成されたXMLを大量のチャンクで書き出すのでなければ、あるいは実装するつもりはありません独自のバッファリングレイヤー。
小さなファイルを扱うのは問題にはなりませんが、特に優れたパフォーマンスと書き込み機能の呼び出しが多々あります。 WriteFileにはかなりのオーバーヘッドがあり、多くの作業を行い、ユーザ→カーネル→ユーザモードスイッチを必要としますが、これは高価です。 "普通のサイズの" XMLファイルを扱っているならば、おそらく大きな違いは見えませんが、大規模なダンプを生成しているなら、頭に入れておくべきことは間違いありません。
あなたが最後の書き込み位置を追跡言及 - liDistanceToMove=0
とdwMoveMethod=FILE_CURRENT
とそれを呼び出すと、現在のファイルを取得する - 最初のオフは、それがファイルバッファを使用すると、生のWin32 APIを使用すると、SetFilePointerEx持ち、ftellを持っている...簡単にする必要があります書込み後の位置。しかし、なぜこれが必要ですか? XMLファイルをストリーミングしている場合は、通常、ストリーミングを続ける必要があります。書き終わったら、ファイルを閉じて再オープンしますか?または、後でさらにデータを挿入する有効なXMLファイルを作成していますか?
Win32ファイル関数のオーバーヘッドは、扱うファイルのサイズによっては、関連する場合とそうでない場合がありますが、ファイルが大きいほど重要ですSimpyがReadFileでメモリにファイルを読み込むマイクロベンチマークであり、コマンドラインから異なるバッファサイズを指定できるようにします。ツールを実行中にProcess ExplorerのIOタブを見るのは面白いことです。ここに私の普通のラップトップ(Win7-SP1 x64、core2duo [email protected]、4GB RAM、120GB Intel-320 SSD)からのいくつかの統計情報があります。
マイクロベンチマークであるかどうかを確認します。あなたの特定の状況では、パフォーマンスは重要ではないかもしれませんが、Win32ファイルAPIにかなりのオーバーヘッドがあり、自分自身を少しバッファリングすることで助けになることが実証されています。4GBのファイル "のみキャッシュミスが発生しますので、大きな" で
BlkSz Speed
32 14.4MB/s
64 28.6MB/s
128 56MB/s
256 107MB/s
512 205MB/s
1024 350MB/s
4096 800MB/s
32768 ~2GB/s
:完全にキャッシュされた2GBのファイルで
BlkSz Speed CPU
32 13MB/s 49%
64 26MB/s 49%
128 52MB/s 49%
256 99MB/s 49%
512 180MB/s 49%
1024 200MB/s 32%
4096 185MB/s 22%
32768 205MB/s 13%
は49%のCPU使用率があることを意味していることを覚えておいてください1つのCPUコアがかなり完全に固定されています。単一のスレッドでは、マシンをずっと強く押すことができません。 2番目の表の4kbバッファの病理学的挙動に注目してください。再現性があり、説明がありません。
安っぽいマイクロベンチマークのコードはここに行く:私の質問は
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <string>
#include <assert.h>
unsigned getDuration(FILETIME& timeStart, FILETIME& timeEnd)
{
// duration is in 100-nanoseconds, we want milliseconds
// 1 millisecond = 1000 microseconds = 1000000 nanoseconds
LARGE_INTEGER ts, te, res;
ts.HighPart = timeStart.dwHighDateTime; ts.LowPart = timeStart.dwLowDateTime;
te.HighPart = timeEnd.dwHighDateTime; te.LowPart = timeEnd.dwLowDateTime;
res.QuadPart = ((te.QuadPart - ts.QuadPart)/10000);
assert(res.QuadPart < UINT_MAX);
return res.QuadPart;
}
int main(int argc, char* argv[])
{
if(argc < 2) {
puts("Syntax: ReadFile [filename] [blocksize]");
return 0;
}
char *filename= argv[1];
int blockSize = atoi(argv[2]);
if(blockSize < 1) {
puts("Please specify a blocksize larger than 0");
return 1;
}
HANDLE hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
if(INVALID_HANDLE_VALUE == hFile) {
puts("error opening input file");
return 1;
}
std::vector<char> buffer(blockSize);
LARGE_INTEGER fileSize;
if(!GetFileSizeEx(hFile, &fileSize)) {
puts("Failed getting file size.");
return 1;
}
std::cout << "File size " << fileSize.QuadPart << ", that's " << (fileSize.QuadPart/blockSize) <<
" blocks of " << blockSize << " bytes - reading..." << std::endl;
FILETIME dummy, kernelStart, userStart;
GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, &kernelStart, &userStart);
DWORD ticks = GetTickCount();
DWORD bytesRead = 0;
do {
if(!ReadFile(hFile, &buffer[0], blockSize, &bytesRead, 0)) {
puts("Error calling ReadFile");
return 1;
}
} while(bytesRead == blockSize);
ticks = GetTickCount() - ticks;
FILETIME kernelEnd, userEnd;
GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, &kernelEnd, &userEnd);
CloseHandle(hFile);
std::cout << "Reading with " << blockSize << " sized blocks took " << ticks << "ms, spending " <<
getDuration(kernelStart, kernelEnd) << "ms in kernel and " <<
getDuration(userStart, userEnd) << "ms in user mode. Hit enter to countinue." << std::endl;
std::string dummyString;
std::cin >> dummyString;
return 0;
}
を否決されたのはなぜ? – Lufia
私は同じことを思っていますが、私はこの質問に何が間違っているのか分かりません。本当に極端なケースでない限り、C++プログラマーは励まされるべきです。 :) –
おかげでマットフィリップス。 – Lufia