2016-09-10 26 views
0

.NET 4.5では、zipアーカイブで動作する新しいクラスが追加されました。あなたが大規模なアーカイブで作業している場合、それはアーカイブからファイルを読み取るために秒あるいは数分かかる場合があり、明らかにSystem.IO.Compressionおよびasync I/OのZipFileおよびZipArchiveクラス

using (ZipArchive archive = ZipFile.OpenRead(zipFilePath)) 
{ 
    foreach (ZipArchiveEntry entry in archive.Entries) 
    { 
     // Extract it to the file 
     entry.ExtractToFile(entry.Name); 

     // or do whatever you want 
     using (Stream stream = entry.Open()) 
     { 
      ... 
     } 
    } 
} 

:今、あなたはこのような何かを行うことができます。したがって、GUIアプリケーション(WinFormsまたはWPF)を作成している場合は、別のスレッドでこのようなコードを実行することになります。そうしないと、UIスレッドがブロックされ、アプリケーションユーザーが非常に不安定になります。

しかし、このコードのすべてのI/O操作が2016年の「クールじゃない」と考えられているblocking modeに実行されるように、2つの質問があります。

  1. はそれが非同期Iを取得することが可能です/ O System.IO.Compressionクラス(または多分他のサードパーティの.NETライブラリと)?
  2. これを行うことは理にかなっていますか?私は圧縮/抽出アルゴリズムはとにかくCPUを消費しているので、 CPUバインドからI/Oを非同期I/Oにブロックする場合でも、パフォーマンスの利得は比較的小さくなります(もちろん、絶対値ではありません) )。

UPDATE:

ピーターDunihoからの回答に返信するには:はい、あなたは正しいです。何らかの理由で私はこのオプションについて考えなかった:

using (Stream zipStream = entry.Open()) 
using (FileStream fileStream = new FileStream(...)) 
{ 
    await zipStream.CopyToAsync(fileStream); 
} 

確かに動作します。ありがとう!

await Task.Run(() => entry.ExtractToFile(entry.Name)); 

はまだちょうど別のスレッドで、CPUバウンドI/O操作をブロックするだろうところで

は、I/O操作中に、スレッドプールからスレッドを消費します。

.NETの開発者は、(アーカイブ内のエントリを列挙するこのコードのように)いくつかのアーカイブ操作でI/Oをブロックしています(ZipArchive.cs on [email protected]など)。私はlack of asynchronous API for ZipFile APIsに関する未解決の問題も発見しました。

私たちは部分非同期サポートをしていると思いますが、完全ではありません。

+0

_ "I/O操作をCPUでブロックすることはありますが、別のスレッドで実行します。" CPUがデータを格納できる速度よりも速くデータを解凍できる限り、それはまだI/Oにバインドされています(しかし、SSDストレージは、より高速な時間を前もって推測することを困難にします)。これは、私が「非同期I/O」の意味に依存していると書いた理由です。すべてのI/Oは本質的に非同期です。これはAPI(たとえば多くの.NET I/Oメソッドが基づいているIOCP)に浮上していることがあります。時にはそうではありません。しかし、I/O操作は、どのように起動するかにかかわらず、CPUを消費しません。 –

+0

はい、そうです、I/O操作はCPUを消費しません。非同期I/Oとは、このI/O操作を要求したスレッドをブロックしないようなAPI関数を意味します。 –

+0

I/O操作がスレッドをブロックするのを避けることができれば、明らかに良いでしょう。しかし、スレッドプールはI/O操作の間にスレッドが一時的にブロックされていると合理的にうまく対処します。主なことは、そうでなければ何か有用なスレッドをブロックしないことです。それが本当に重要なのであれば、 'ExtractToFile()'のようなメソッドは、スレッドを使わない真の非同期I/Oメソッドとして実装するのは簡単です(既に上記のアップデートで示したように)。 –

答えて

2
  1. はそれがSystem.IO.Compressionクラス(または多分いくつかの他のサードパーティの.NETライブラリを使用)とI/O非同期(async)を取得することは可能ですか?

あなたが実際にあなたは組み込みの.NET型でそれを行うことができ、「非同期I/O」の意味内容に応じて。たとえば、

using (ZipArchive archive = await Task.Run(() => ZipFile.OpenRead(zipFilePath))) 
{ 
    foreach (ZipArchiveEntry entry in archive.Entries) 
    { 
     // Extract it to the file 
     await Task.Run(() => entry.ExtractToFile(entry.Name)); 

     // or do whatever you want 
     using (Stream stream = entry.Open()) 
     { 
      // use XXXAsync() methods on Stream object 
      ... 
     } 
    } 
} 

これらを囲む場合は、拡張方法XXXAsync()です。

  1. これは意味がありますか?とにかく圧縮/抽出アルゴリズムが非常にCPUを消費していることを意味しています。したがって、CPUバインドI/Oから非同期I/Oに切り替える場合でも、パフォーマンスの向上は比較的小さい(もちろん絶対値ではありません)。それを行うには

少なくとも三つの理由:

  1. CPUは非常に高速です。多くの場合、I/Oは依然としてボトルネックなので、I/Oを非同期的に待つことは便利です。
  2. マルチコアCPUが標準です。したがって、あるコアが減圧に取り組んでいる間に別の作業をするのが便利です。
  3. 非同期操作は、パフォーマンスに関して完全ではなく、場合によってはまったくではありません。アーカイブを非同期に処理することで、ユーザーインターフェイスの応答性を保つことができ、便利です。
関連する問題