ZipFile 和 ZipArchive 类 来自 System.IO.Compression 和异步 I/O
ZipFile and ZipArchive classes from System.IO.Compression and async I/O
.NET 4.5 添加了新的 类 以处理 zip 存档。现在你可以这样做:
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操作都将在blocking mode中执行,在2016年被认为是"not cool"。所以有两个问题:
- 是否可以使用
System.IO.Compression
类(或者可能使用其他第三方 .NET 库)获得异步 I/O?
- 这样做有意义吗?我的意思是 compressing/extracting 算法无论如何都非常 CPU-consuming,所以如果我们甚至从
CPU-bound 阻塞 I/O 切换到异步I/O,性能提升可以比较小(当然是百分比,不是绝对值)。
更新:
回复 Peter 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 dotnet@github). I also found an open issue about the lack of asynchronous API for ZipFile APIs.
我想此时我们有部分异步支持,但还远未完成。
- Is it possible to get async I/O with
System.IO.Compression
classes (or maybe with some other third-party .NET library)?
根据 "async I/O" 的实际含义,您可以使用内置的 .NET 类型来实现。例如:
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()
扩展方法中。
- Does it even make sense to do that? I mean compressing/extracting algorithms are very CPU-consuming anyway, so if we even switch from CPU-bound I/O to async I/O, the performance gain can be relatively small (of course in percentage, not absolute values).
至少有三个这样做的理由:
- CPU 非常快。在许多情况下,I/O 仍然是瓶颈,因此异步等待 I/O 很有用。
- 多核 CPU 是常态。因此,让一个核心处理减压而另一个核心处理其他工作很有用。
- 异步操作不完全是关于性能的,在某些情况下根本不是。异步处理您的档案允许用户界面保持响应,这很有用。
.NET 4.5 添加了新的 类 以处理 zip 存档。现在你可以这样做:
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操作都将在blocking mode中执行,在2016年被认为是"not cool"。所以有两个问题:
- 是否可以使用
System.IO.Compression
类(或者可能使用其他第三方 .NET 库)获得异步 I/O? - 这样做有意义吗?我的意思是 compressing/extracting 算法无论如何都非常 CPU-consuming,所以如果我们甚至从
CPU-bound阻塞 I/O 切换到异步I/O,性能提升可以比较小(当然是百分比,不是绝对值)。
更新:
回复 Peter 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 dotnet@github). I also found an open issue about the lack of asynchronous API for ZipFile APIs.
我想此时我们有部分异步支持,但还远未完成。
- Is it possible to get async I/O with
System.IO.Compression
classes (or maybe with some other third-party .NET library)?
根据 "async I/O" 的实际含义,您可以使用内置的 .NET 类型来实现。例如:
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()
扩展方法中。
- Does it even make sense to do that? I mean compressing/extracting algorithms are very CPU-consuming anyway, so if we even switch from CPU-bound I/O to async I/O, the performance gain can be relatively small (of course in percentage, not absolute values).
至少有三个这样做的理由:
- CPU 非常快。在许多情况下,I/O 仍然是瓶颈,因此异步等待 I/O 很有用。
- 多核 CPU 是常态。因此,让一个核心处理减压而另一个核心处理其他工作很有用。
- 异步操作不完全是关于性能的,在某些情况下根本不是。异步处理您的档案允许用户界面保持响应,这很有用。