質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

3回答

5718閲覧

マップトメモリの書き込み速度

sadokazu

総合スコア14

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

3クリップ

投稿2019/04/07 23:53

マップトメモリを使用してプロセス間のデータ共有で使用しようと考えておりますが

3000×3000の24bit Bitmapのbyte配列をメモリに書き込むのにやけに時間がかかっている様に思え、これが正常なのかどうかが知りたいです

bmp.saveでRAMディスク等に書き込んだ方が速いのですが、何か間違っているのでしょうか?

プロセス間のメモリ共有については問題無く使用できますが・・・。

よろしくお願いします

c#

1MemoryMappedFile mmf; 2 3Bitmap bmp = new Bitmap(Application.StartupPath + "\Test.bmp"); // 容量の大きいBitmapファイル 4byte[] bytBmp = new byte[bmp.Width * bmp.Height * 3]; 5 6BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 7Marshal.Copy(bmpData.Scan0, bytBmp, 0, bytBmp.Length); // Marshal Copyは大体50msくらいでコピーできる 8bmp.UnlockBits(bmpData); 9 10 11mmf = MemoryMappedFile.CreateNew("input", bytBmp.Length); 12MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(); 13 14accessor.WriteArray<byte>(0, bytBmp, 0, bytBmp.Length);    // だいたい600~700msくらいかかる 15accessor.Dispose(); 16

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2019/04/08 00:01

そりゃ HDD 使ってるのでメモリと比べるのが間違ってます。
sadokazu

2019/04/08 00:09

メモリ上にマッピングしている ↓ メモリに書き込んでいる という解釈でしたが違うと言うことですね。 BitmapはHDDにSaveしても100msくらいで保存出来ますが、それ以下の速度になっています。 ちなみに厳密にはHDDではなくSSDでbmp.saveに90ms、マップトメモリでは600msで
Zuishin

2019/04/08 01:01

メモリマップトファイルというのはメモリにマッピングされたファイルです。 メモリへの書き込み・読み込みと同じ手続きでファイルへの書き込み・読み込みができるようになります。 実際に使われているのが HDD か SSD か私が知るわけがありませんが、当然普通にアクセスするよりオーバーヘッドがあります。
sadokazu

2019/04/08 01:48

なるほど。理解致しました。 丁寧な回答ありがとうございます。
guest

回答3

0

メモリマップドファイルと遅いという結論になってしまっていますが、実際には違います。提示されているコードが遅い原因は MemoryMappedViewAccessor.WriteArray の実装に起因しています。メモリマップドファイルは効率的にディスクアクセスするため、ディスクとマッピングした場合も該当ディスクに対するシーケンシャル書き込みに準じた性能が出るはずです。ディスクにマッピングしない場合は通常のメモリアクセスよりやや遅いていどの速度にはなるはずです。コメントに記載されている5倍以上の速度差というのはちょっと考えられません。

MemoryMappedViewAccessor.WriteArray は最終的に以下のメソッドによって処理されています。
SafeBuffer.WriteArray
このメソッドを見ていただくとわかる通り、GenericStructureToPtr メソッドをループして呼び出しているだけです。3000 x 3000 の 24 ビットビットマップであれば、これを 2700 万回繰り返して呼び出すために提示されているぐらいの時間がかかっていると推測されます。

単純にバイト書き込みだけであれば、以下のように MemoryMappedViewStream を使用すると高速化可能です。これで単純なメモリコピーの 2 倍ぐらいの速度にはなるかと思います。

C#

1 using (var stream = mmf.CreateViewStream()) 2 { 3 stream.Write(bytBmp, 0, bytBmp.Length); 4 } 5

なお、CreateViewStream の実装にも速度低下の原因があり、同サイズの領域をゼロ埋めする処理があるため通常のメモリコピーの倍ぐらいの速度になってしまっています。速度最速を目指すのであれば、MemoryMappedFile.SafeMemoryMappedFileHandle に対して MapViewOfFile を呼び出して生のポインタを取り出して書き込むとメモリアクセス速度と同程度にはなります。

投稿2019/04/08 15:40

編集2019/04/08 15:43
atata0319

総合スコア881

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2019/04/08 16:26

横からすみません。私の方でも質問者さんのコードをHDD(読み書き共に約180MB/s)上で追試したとき、結果が同じ傾向を示していて、コード前半のファイルからの読み出し部分はCrystalDiskMarkで報告されるシーケンシャル読み出し速度にだいたい一致していたものの、MemoryMappedViewAccessor.WriteArray の書き込み速度は大きく違っていて解せませんでした。ご提示のMemoryMappedViewStreamでの方法で書き込み速度も同様に一致するようになりました。大変参考になりました。
sadokazu

2019/04/08 23:35

メモリへの読み書きと同じようにファイルへの読み書きができる=速度はファイル作成と同じ という解釈になっておりました。(単純にファイル作成より遅いようにも思いましたが・・・) ご指摘していただいたコードで確認したところ、Marshal.copyと同じ程度まで速度向上させることができました。 大変参考になりました。 ありがとうございました。
guest

0

マップトメモリによる高速化とは、ボトルネックである物理ファイルのI/Oを最小限に抑えるロジックを組む事にほかなりません。
けして物理ファイルのI/O自体が速くなるわけではありません。
どんなロジックを組むかは、目的次第です。
例えばBMPの中の一部の矩形範囲を編集するなら、対象の領域は連続しないですよね。
その場合は複数の領域に対してViewを作り、その複数のViewを統合して疑似的に一つのストリームとしてアクセスするようにするなど。

投稿2019/04/08 02:08

hihijiji

総合スコア4150

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自己解決

質問への追記にてマップトメモリでの共有について理解しました。
ありがとうございます

投稿2019/04/08 02:00

sadokazu

総合スコア14

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問