ZIPファイルをSharpZipLibというライブラリを使って展開してみます。
プロジェクトの作成
cd (mkdir SharpZipLibSample01)
dotnet new console -f net8.0
dotnet add package SharpZipLib --version 1.4.2
ソースコード
直列処理版
ファイル名:Program.cs
using System.Diagnostics;
using System.Security.AccessControl;
using ICSharpCode.SharpZipLib.Zip;
// zipEntries は List<string>(エントリ名のリスト)を想定
var stopwatch = Stopwatch.StartNew();
const string OUTPUT_DIR = @"./output";
const string INPUT_ACHIVE_FILE = @"G:\testdata\Archive.zip";
Directory.CreateDirectory(OUTPUT_DIR!);
List<string> zipEntries;
using (var fs = File.OpenRead(INPUT_ACHIVE_FILE))
using (var zip = new ZipFile(fs))
{
zipEntries = zip.Cast<ZipEntry>()
.Where(e => !e.IsDirectory)
.Select(e => e.Name)
.ToList();
}
using var zipStream = File.OpenRead(INPUT_ACHIVE_FILE);
using var zipFile = new ZipFile(zipStream);
foreach (var entryName in zipEntries)
{
var entry = zipFile.GetEntry(entryName);
if (entry == null || entry.IsDirectory) continue;
using var entryStream = zipFile.GetInputStream(entry);
var outPath = Path.Combine(OUTPUT_DIR, entry.Name);
using var outFile = File.Create(outPath);
entryStream.CopyTo(outFile);
}
stopwatch.Stop();
Console.WriteLine($"直列処理時間: {stopwatch.ElapsedMilliseconds} ms");
並列処理版
using System.Diagnostics;
using System.Security.AccessControl;
using ICSharpCode.SharpZipLib.Zip;
// zipEntries は List<string>(エントリ名のリスト)を想定
var stopwatch = Stopwatch.StartNew();
const string OUTPUT_DIR = @"./output";
const string INPUT_ACHIVE_FILE = @"G:\testdata\Archive.zip";
Directory.CreateDirectory(OUTPUT_DIR!);
List<string> zipEntries;
using (var fs = File.OpenRead(INPUT_ACHIVE_FILE))
using (var zip = new ZipFile(fs))
{
zipEntries = zip.Cast<ZipEntry>()
.Where(e => !e.IsDirectory)
.Select(e => e.Name)
.ToList();
}
using var zipStream = File.OpenRead(INPUT_ACHIVE_FILE);
using var zipFile = new ZipFile(zipStream);
var options = new ParallelOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount / 1
};
// zipEntries は List<string>
Parallel.ForEach(zipEntries, options, entryName =>
{
using var zipStream = File.OpenRead(INPUT_ACHIVE_FILE); // 各スレッドで独立に開く
using var zipFile = new ZipFile(zipStream);
var entry = zipFile.GetEntry(entryName);
if (entry == null || entry.IsDirectory) return;
using var entryStream = zipFile.GetInputStream(entry);
var outPath = Path.Combine("output", entry.Name);
using var outFile = File.Create(outPath);
entryStream.CopyTo(outFile);
});
stopwatch.Stop();
Console.WriteLine($"並列処理時間(MaxThreads={options.MaxDegreeOfParallelism}): {stopwatch.ElapsedMilliseconds} ms");
実行結果
実行環境
Ryzen7 5700X (8コア16スレッド)
・ZIPファイルはNVMeSSDから読み出し、出力先もNVMeSSD
直列処理時間: 499 ms
並列処理時間(MaxThreads=1): 529 ms
並列処理時間(MaxThreads=2): 338 ms
並列処理時間(MaxThreads=4): 247 ms
並列処理時間(MaxThreads=8): 212 ms
並列処理時間(MaxThreads=16): 228 ms
・ZIPファイルはNAS(HDD)から読み込み。出力先はNVMeSSD
直列処理時間: 2220 ms
並列処理時間(MaxThreads=1): 5545 ms
並列処理時間(MaxThreads=2): 2877 ms
並列処理時間(MaxThreads=4): 3193 ms
並列処理時間(MaxThreads=8): 4042 ms
並列処理時間(MaxThreads=16): 3940 ms
NVMeSSDの場合は並列処理で効率が上がるようだが、NAS(HDD)の場合直列処理のほうが高速に動作します。
コメント