こんにちは。いつも参考にさせていただいております。
Win2K SP4 VC++6 SP5 で開発をしております。
ファイル書き込みに関して、もやもやしており質問させてください。
Win32SDKのCreateFileで1つのファイルを生成します。
このファイルに対して、
WriteFile、FlushFileBuffersで書き込みをかける場合と、
CreateFileMapping、MapViewOfFileで仮想メモリ化した上で
書き込みをかける場合のどちらが通常選ばれるものでしょうか?
ファイルの最大サイズとしては8MB程度を想定しています。
このファイルには1プロセスからしかアクセスしない決まりがあり、
プロセス間通信に使用するものではありません。
また、ファイルハンドルへのアクセス時には、
スレッド間の排他にクリティカルセクションを使用します。
仮想メモリ化するとあらかじめ指定のサイズでファイルが
作成されるため、WriteFileを使用する場合にくらべ
ハーディディスクへの書き込み時間が早いなどの理由が
あれば仮想メモリのほうが良い気がするのですが、
Pen4 3.2Ghz、メモリ1GBの環境ですと、
スレッドを1000個ほど立ち上げて同時に書き込んだとしても
ほとんど性能に差はありません。
皆様よろしくお願いします。
どういう手順でファイルを作るにせよ、
本当にディスクメディア上にファイルを作るのであれば (メモリ上の擬似ファイルでなく)
律速となるのはディスク自体の速度でしょう。
差が出なくて当然なような気がします。
質問の意味が分りません。
「CreateFileMapping」を使ってなにをしたいのかが分りません。
>Win32SDKのCreateFileで1つのファイルを生成します。
をした後で、「CreateFileMapping」や「MapViewOfFile」を行っても
何も変わらないと思います。
パズさんが実際に行いたいことを示して下さい。
tetrapodさん、ITOさん、ご返答ありがとうございます。
分かりにくい質問をしてしまって申し訳ありません。
私が「CreateFileMapping」について理解が足りないのかもしれません。
私はこれまで、「CreateFileMapping」は異なるプロセス間で
データ共有に使用するものだと認識しています。
ですが、他人が書いたソースを読む機会があり、
1プロセスからしかアクセスしないファイルへの書き込みを行う際に
性能を考慮して「CreateFileMapping」を使用するとのコメントが
あったため、「え、早くなるの?」と思った次第です。
。。。変わらないようですね。
ありがとうございました。
>私はこれまで、「CreateFileMapping」は異なるプロセス間で
>データ共有に使用するものだと認識しています。
会っていると思います。
「CreateFileMapping」でファイルへの書き込みが早くなるのは、
「CreateFileMapping」で作成したメモリー領域をファイルの
データ領域に使うからだと認識しています。
#間違っていたらフォロ-お願いします。
もちろん、メモリーに書いたデータは最後ディスクに書かなければならないです。
僕は、MFCの「CMemFile」を使ったことがあります。
訂正します。
>会っていると思います。 誤
正 それで正しいと思います。
実際に測定したわけじゃないので間違えているかもしれません。
毎回アクセスしたい位置をif文で判断して
今まで使用していたバッファを保存したり
次のデータをバッファへ読み込みしたりしますよね。
これに対し
メモリ不足のときにページアウトする機能を利用して保存とする。
また確保していないアドレスの読み込みをすると
ページフォルト例外が起きてページインを行うのを読み込みとする。
if文がいらなくなる。←速くなる
読み書きのコードも書かなくていい。←OSの仮想メモリの機能だから効率のいいコード
だろう。
fwrite で CRTL 経由しようが
WriteFile で CRTL をバイパスして OS を直呼びしようが
*p=a; として OS のページ例外を使おうが
ボトルネックな場所で速度は決まり、それは現状ディスク装置です。
# i-RAM とか使えば S-ATA の転送速度になるでしょうけど
「効率のいい」「性能を考慮」の文言の意図次第ですな。
自作ソフトのサイズ=効率であるなら *p=a; が一番効率がイイ。
アプリケーション上の命令語は mov 命令1個になるわけだし。
以下の順だった。
(1)メモリマップトファイル
(2)適当なサイズのバッファを使う
(3)ファイルサイズと同じサイズのバッファを使う
(2)は、
1MBとか適当なサイズのバッファを用意して、
毎回アクセスしたい位置をif文で判断して
今まで使用していたバッファを保存したり
次のデータをバッファへ読み込みしたりする。
(3)は、
ファイルサイズと同じサイズのバッファを用意して、
読み書きは一度だけ。
(3)はサイズが大きいほど(2)より遅くなる。
スラッシングが起きればどの方法も遅い(念のため)。
(念のため)メモリマップトファイルを良く知らないので間違えているかもしれませ
ん。
予めサイズ指定することでHDDの何処にページインアウトするか予約済みなので敏速だと
思う。
サイズ制限があるから使えない用途があるのが残念だ。
CreateFileMappingの使い方は、
(1) 8MB?の領域を確保する。
(2) 「CreateFile」を行う。
(3) 「CreateFileMapping」で「CreateFile」のハンドルから、
MapHandleを得る。
(4) 「MapViewOfFile」の戻り値で、確保した領域を指定する。
(5) 確保した領域に変更を加える。
(6) 「UnmapViewOfFile」で変更結果がファイルに反映される。
(7) 「CloseHandle」
まだ、やったことはないですが、このような作業になるようです。
みなさま、ご無沙汰してしまって申し訳ありません。
>(1) 8MB?の領域を確保する。
>(2) 「CreateFile」を行う。
>(3) 「CreateFileMapping」で「CreateFile」のハンドルから、
> MapHandleを得る。
>(4) 「MapViewOfFile」の戻り値で、確保した領域を指定する。
>(5) 確保した領域に変更を加える。
>(6) 「UnmapViewOfFile」で変更結果がファイルに反映される。
>(7) 「CloseHandle」
この手順を前提に質問していました。
説明が悪すぎたようで申し訳ありません。。
(5)のところで何度もファイルに書き込みを行う場合、
・上記の手順でファイルに書き込む場合
(プログラムの最初で(4)まで行っておき、プログラム終了時に
(7)でファイルハンドルと「CreateFileMapping」した
ハンドルを閉じる)
・(2)でCreateFileしたハンドルに対してWriteFileで書きこむ場合
とで、一般的にどちらが選ばれるものでしょうか?
ということを質問したつもりでした。
性能に関しては、tetrapodさんがおっしゃるように、
結局HDDがボトルネックになるのだから、
結果的に変わらないのだろうと理解しました。
ただし、超初心者さんがおっしゃるように、
「CreateFileMapping」のほうはあらかじめ領域固定でスワップ領域が
確定しているので、WriteFileで書き込むたびにファイルサイズがすこしずつ
増加していくよりも早いのではないか。
と理解しました。
皆様ありがとうございました。
「CreateFileMapping」、「MapViewOfFile」、「UnmapViewOfFile」は、
WriteFileやReadFileを使いません。
「MapViewOfFile」で指定されたメモリ空間を直接書換えます。
「MapViewOfFile」を実行したときファイルの内容は、メモリー空間にすべて
読み込まれます。
「UnmapViewOfFile」により、メモリー空間の内容がファイルに書込まれます。
「CreateFileMapping」、「MapViewOfFile」、「UnmapViewOfFile」の使用条件は、
指定したメモリ空間 = ファイルの容量です。
今回調べてみましたが、以上の内容でした。
ファイルの書込み・読込みをファイルでなくメモリーに対して
おこないたいのであれば、「CMemFile」を使うのがいいと思います。
MFCの関数です。