C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[2]: マルチthreadでファイルを読み込むメリットについて


(過去ログ 176 を表示中)

[トピック内 13 記事 (1 - 13 表示)]  << 0 >>

■100952 / inTopicNo.1)  マルチthreadでファイルを読み込むメリットについて
  
□投稿者/ 弥生 (1回)-(2022/12/05(Mon) 13:27:28)

分類:[討論] 

OS問わず、一般的な原理からすれば、
マルチthreadでハードディスクの中から多量なファイルを『同時に』メモリに読み込む場合、
必ず、シングルthreadで一つ一つのファイルを読み込む場合より、
マクロ的(巨視的)に時間節約できると言えるのでしょうか。



引用返信 編集キー/
■100953 / inTopicNo.2)  Re[1]: マルチthreadでファイルを読み込むメリットについて
□投稿者/ 弥生 (2回)-(2022/12/05(Mon) 13:29:46)
追伸:
ここではハードディスクが一枚しかないとします。

引用返信 編集キー/
■100954 / inTopicNo.3)  Re[1]: マルチthreadでファイルを読み込むメリットについて
□投稿者/ kiku (313回)-(2022/12/05(Mon) 13:44:37)
No100952 (弥生 さん) に返信
> OS問わず、一般的な原理からすれば、
> マルチthreadでハードディスクの中から多量なファイルを『同時に』メモリに読み込む場合、
> 必ず、シングルthreadで一つ一つのファイルを読み込む場合より、
> マクロ的(巨視的)に時間節約できると言えるのでしょうか。

ハードディスク側がマルチスレッドに対応した場合には
読取側がマルチスレッドに対応する意味があると思いますが、
通常、同時に複数のアクセスはできないため、
時間節約にならないです。
※ハードディスクだけではなくて、システムBUSなども
 複数チャンネルを扱えるようにしないと。。。。

逆に、スレッドの切り替えによる時間ロスなどが
発生し、かえってマルチスレッド化によって
より多くの時間を要することになる可能性の方が
高くなると思います。
引用返信 編集キー/
■100955 / inTopicNo.4)  Re[1]: マルチthreadでファイルを読み込むメリットについて
□投稿者/ WebSurfer (2590回)-(2022/12/05(Mon) 13:55:03)
No100952 (弥生 さん) に返信
> OS問わず、一般的な原理からすれば、
> マルチthreadでハードディスクの中から多量なファイルを『同時に』メモリに読み込む場合、
> 必ず、シングルthreadで一つ一つのファイルを読み込む場合より、
> マクロ的(巨視的)に時間節約できると言えるのでしょうか。

あなたの言う「OS問わず、一般的な原理」というところがどこまで拡張しての話なのか分
かりませんが、.NET アプリの場合であれば「時間節約」は目的にはならないケースが多
いと思います。

Windows Forms や WPF など GUI アプリであれば UI の応答性の向上、ASP.NET アプリで
あれば限られたスレッドプールスレッドを有効利用してスループットの向上が目的になり
ます。

いずれも処理時間の短縮は目的ではありません。
引用返信 編集キー/
■100956 / inTopicNo.5)  Re[1]: マルチthreadでファイルを読み込むメリットについて
□投稿者/ 774RR (891回)-(2022/12/05(Mon) 15:28:34)
まったくもって時間節約にならないどころか逆効果=超絶遅くなるだけでしょう。
プラッタ上連続位置に記録されているファイル内容を読むのがハードディスク装置の原理上最速で、
となるとシングルスレッドで同時には1ファイルを読むのが最速です。
違うファイルを交互に読むと必ずシーク・回転待ち時間が発生し、その間はデータは一切得られないわけで遅くなるだけです。

体感したかったら1台の CD/DVD 装置からハードディスク装置へコピーする、を2つ以上同時に実行してみるとヨシ
( Explorer でドラッグコピーするだけでできる・プログラムなど書かなくていい)


引用返信 編集キー/
■100957 / inTopicNo.6)  Re[1]: マルチthreadでファイルを読み込むメリットについて
□投稿者/ KOZ (361回)-(2022/12/05(Mon) 16:21:52)
2022/12/06(Tue) 00:27:33 編集(投稿者)
No100952 (弥生 さん) に返信
> OS問わず、一般的な原理からすれば、
> マルチthreadでハードディスクの中から多量なファイルを『同時に』メモリに読み込む場合、
> 必ず、シングルthreadで一つ一つのファイルを読み込む場合より、
> マクロ的(巨視的)に時間節約できると言えるのでしょうか。

どうしても待ち時間というのは発生してしまうので、シングルスレッドで
ハードウエアのパフォーマンスを 100% 引き出すことは難しいです。
うまく使えば時間節約できるでしょう。

C# でサンプルを書いてみました。
ディスクキャッシュが効いていると、マルチスレッドのほうが有利なので、
FILE_FLAG_NO_BUFFERING オプションを付けてキャッシュ無効で読み込んでます。
スレッド数やバッファ長などいろいろ変えて試してみてください。

ちょっと修正

・定数を先頭に
・スレッドで処理するファイル数の余りを均等に
・ファイル単位で確保した読み取りバッファをスレッド単位に

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

class Program
{
    const int FILE_FLAG_NO_BUFFERING = 0x20000000;
    const int MAX_THREADS = 10;
    const int BUFFER_SIZE = 1024 * 1024 * 10; // 512 の整数倍でないとコケる

    static void Main(string[] args) {
        var targetDir = Environment.ExpandEnvironmentVariables(@"%WINDIR%\System32");
        var files = Directory.GetFiles(targetDir);
        Watch($"** Multi({MAX_THREADS}) **", () => { Multi(files, MAX_THREADS); });
        Watch("** Single **", () => { Single(files); });
        Console.ReadKey();
    }

    static void Watch(string message, Action action) {
        var sw = new Stopwatch();
        sw.Start();
        action.Invoke();
        sw.Stop();
        Console.WriteLine($"{message} {sw.ElapsedMilliseconds} ms");
    }

    static void Multi(string[] files, int threads) {
        int allCount = files.Length;
        int splitCount = allCount / threads;
        int remainder = allCount % threads;
        int[] counts = Enumerable.Repeat(splitCount, threads).ToArray();
        for (int i = 0; i < remainder; i++) {
            counts[i] = splitCount + 1;
        }
        Task[] tasks = new Task[threads];
        int position = 0;
        for (int i = 0; i < threads; i++) {
            int start = position;
            int count = counts[i];
            tasks[i] = Task.Factory.StartNew(() => { ReadFiles(files, start, count); });
            position += count;
        }
        Task.WaitAll(tasks);
    }

    static void Single(string[] files) {
        ReadFiles(files, 0, files.Length);
    }

    static void ReadFiles(string[] files, int start, int count) {
        Console.WriteLine($"start={start} count={count}");
        byte[] buffer = new byte[BUFFER_SIZE];
        for (int i = 0; i < count; i++) {
            ReadFile(files[start + i], buffer);
        }
    }

    static void ReadFile(string file, byte[] buffer) {
        FileOptions options = (FileOptions)FILE_FLAG_NO_BUFFERING;
        using (var stream = new FileStream(file, FileMode.Open, 
                                    FileAccess.Read, FileShare.Read,
                                    BUFFER_SIZE, options)) {
            while (stream.Read(buffer, 0, BUFFER_SIZE) == BUFFER_SIZE) { }
        }
    }
}

引用返信 編集キー/
■100958 / inTopicNo.7)  Re[2]: マルチthreadでファイルを読み込むメリットについて
□投稿者/ kiku (314回)-(2022/12/05(Mon) 16:33:50)
No100954 (kiku さん) に返信
> ■No100952 (弥生 さん) に返信
> ハードディスク側がマルチスレッドに対応した場合には
> 読取側がマルチスレッドに対応する意味があると思いますが、
> 通常、同時に複数のアクセスはできないため、
> 時間節約にならないです。
> ※ハードディスクだけではなくて、システムBUSなども
>  複数チャンネルを扱えるようにしないと。。。。

上記のようなHDDは存在するのかどうか気になって
検索したところ、やっぱりあるみたいですね。
https://hardware.srad.jp/story/17/12/21/0720217/

上記は複数ヘッドが存在し、それぞれヘッドが独立して
動くようです。

特殊ばハードを用意すれば、できなくはないということですね。
一般利用では難しいとは思いますが。
引用返信 編集キー/
■100959 / inTopicNo.8)  Re[2]: マルチthreadでファイルを読み込むメリットについて
□投稿者/ 弥生 (3回)-(2022/12/05(Mon) 17:30:13)
皆様
ご教授ありがとうございます!

多くの方のご意見良く分かりました。

自分のイメージはどちらかと言うと、KOZさまがおっしゃったのと似ています。

キャッシュやバッファリングの存在と機械動きの間で同時性があって、
シークの間に他のthreadが他のthreadの読みこぼれの中から自分の目標ファイルのデータを読み込むという印象。。。

メモリ関係の記憶と間違えたかもしれませんが、
確かメモリには幾つかのレベルがあって、毎回所要サイズ分のデータのみ外部メモリからCPU内蔵のメモリに読み込むのではなく、
一定量の大きな塊を読み込んでキャッシュして、CPUが必要なデータはまずそのキャッシュバッファから探します。
あれば利用しますし、なければ、初めて外部メモリから読み込みます。


HDDも同じ原理で働いているのでは?と記憶が曖昧で申し訳ございません。
要は、某ターゲットファイルを読み込む時に、必ずそのファイルの記録位置と物理的に近傍する他のファイルのデータも一緒にキャッシュされ、
他のファイルを読み込もうとする時にまずは、HDDバッファから読もうとし、無ければ、HDDにアクセス。。。
これで、複数のthread同士の同時読み込む事は可能になるような感じですね。

自分が勘違いである可能性が高いので、皆さんにもう一度ご指導お願い致します。


◆◆◆◆◆◆◆◆

KOZさま、わざわざ高度なコードまで組んでいただきまして、
誠に感謝致します。

とりあえずそのコードをじっくり勉強致します。








引用返信 編集キー/
■100961 / inTopicNo.9)  Re[3]: マルチthreadでファイルを読み込むメリットについて
□投稿者/ KOZ (362回)-(2022/12/05(Mon) 19:11:00)
No100959 (弥生 さん) に返信

たとえば、私のコードだと System32 ディレクトリ上のファイルを読みだしているわけですが
10MB 以下のファイルがほとんどなので、バッファサイズを 10MB にしてみると、かなり改善されます。
小さいファイルをたくさん読み出しする場合、マルチスレッドである利点が生かしやすいと思います。

反面、HDD のキャッシュに乗らないような数百MB のファイルを読み出す場合、
アームがあちこち動くことになるのでマルチスレッドであることが逆効果に
なってしまうかもしれません。

常にどちらが有利、ということは言えず、状況による、としか言いようがないと思います。

引用返信 編集キー/
■100962 / inTopicNo.10)  Re[2]: マルチthreadでファイルを読み込むメリットについて
□投稿者/ KOZ (363回)-(2022/12/05(Mon) 23:44:22)
2022/12/06(Tue) 00:09:59 編集(投稿者)

No100957 (KOZ) に返信
> スレッド数やバッファ長などいろいろ変えて試してみてください。

いろいろ変えて試してみたんですが、バッファ長は 512 の整数倍でなければならないようです。

256 とか 1000 等にすると

ArgumentException: ハンドルは同期操作をサポートしません。FileStream コンストラクターへのパラメーターは、ハンドルが非同期的に開かれた (つまり、ハンドルはオーバーラップされた I/O に対して明示的に開かれた) ことを示すために、変更する必要があります。

というわけのわからないエラーが出ますので、ご注意ください。

FILE_FLAG_NO_BUFFERING を指定したときの制限のようです。
https://learn.microsoft.com/ja-jp/windows/win32/fileio/file-buffering

引用返信 編集キー/
■100964 / inTopicNo.11)  Re[3]: マルチthreadでファイルを読み込むメリットについて
□投稿者/ KOZ (364回)-(2022/12/06(Tue) 09:06:17)
No100959 (弥生 さん) に返信

詳しく考察している人がいらっしゃいました。

「Performance Impact of Parallel Disk Access」
https://pkolaczk.github.io/disk-parallelism/

「Ordering Requests to Accelerate Disk I/O」
https://pkolaczk.github.io/disk-access-ordering/

HDD のランダムアクセスでは、キューに積み上げられた要求を、
もっとも効率よくアクセスできるよう、OS が並び替えているようです。


引用返信 編集キー/
■100976 / inTopicNo.12)  Re[4]: マルチthreadでファイルを読み込むメリットについて
□投稿者/ RUNE (3回)-(2022/12/07(Wed) 11:17:29)
No100964 (KOZ さん) に返信
> ■No100959 (弥生 さん) に返信

KOZさま
貴重な情報と素晴らしい結果本当に有り難いです!

自分が普段利用しているファイルが
たぶんランダムアクセスのものばかりだと思いますので、
マルチスレッドでファイルアクセスを活用したいですね。

再度お礼を申し上げます。


解決済み
引用返信 編集キー/
■100977 / inTopicNo.13)  Re[5]: マルチthreadでファイルを読み込むメリットについて
□投稿者/ 弥生 (4回)-(2022/12/07(Wed) 11:18:47)
No100976 (RUNE さん) に返信
> ■No100964 (KOZ さん) に返信
>>■No100959 (弥生 さん) に返信
>
> KOZさま
> 貴重な情報と素晴らしい結果本当に有り難いです!
>
> 自分が普段利用しているファイルが
> たぶんランダムアクセスのものばかりだと思いますので、
> マルチスレッドでファイルアクセスを活用したいですね。
>
> 再度お礼を申し上げます。
>
>
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -