我们有一个现有的库,其中一些方法需要转换为异步方法。
但是我不确定如何使用以下方法执行此操作(错误处理已被删除)。该方法的目的是压缩文件并将其保存到磁盘。 (请注意,zip类不会公开任何异步方法。)
public static bool ZipAndSaveFile(string fileToPack, string archiveName, string outputDirectory)
{
var archiveNameAndPath = Path.Combine(outputDirectory, archiveName);
using (var zip = new ZipFile())
{
zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
zip.Comment = $"This archive was created at {System.DateTime.UtcNow.ToString("G")} (UTC)";
zip.AddFile(fileToPack);
zip.Save(archiveNameAndPath);
}
return true;
}
实现可能如下所示:
public static async Task<bool> ZipAndSaveFileAsync(string fileToPack, string archiveName, string outputDirectory)
{
var archiveNameAndPath = Path.Combine(outputDirectory, archiveName);
await Task.Run(() =>
{
using (var zip = new ZipFile())
{
zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
zip.Comment = $"This archive was created at {System.DateTime.UtcNow.ToString("G")} (UTC)";
zip.AddFile(fileToPack);
zip.Save(archiveNameAndPath);
}
});
return true;
}
这似乎不对。客户端可以使用Task.Run
调用sync方法请问,任何人都有关于如何将其转换为异步方法的任何提示吗?
答案 0 :(得分:1)
这似乎不对。客户端可以调用sync方法 使用Task.Run
点亮。通过在Task.Run()中包装同步代码,库现在正在使用客户端的线程池资源,而不是很明显。想象一下,如果所有库采用这种方法,客户端的线程池会发生什么?简而言之,只需公开同步方法,让客户决定是否要将其包装在Task.Run()中。
话虽如此,如果ZipFile对象具有异步功能(例如具有SaveAsync()方法),那么您也可以使外部方法异步。这是一个看起来如何的例子:
(s3/get-object :bucket-name "my-bucket" :key "foo"
:sdk-client-execution-timeout 10000)
答案 1 :(得分:1)
作为临时解决方案,我将介绍一种扩展方法:
public static class ZipFileExtensions
{
public static Task SaveAsync(this ZipFile zipFile, string filePath)
{
zipFile.Save(filePath);
return Task.FromResult(true);
}
}
然后用法是:
public static async Task<bool> ZipAndSaveFileAsync(string fileToPack, string archiveName, string outputDirectory)
{
var archiveNameAndPath = Path.Combine(outputDirectory, archiveName);
using (var zip = new ZipFile())
{
...
await zip.SaveAsync(archiveNameAndPath).ConfugureAwait(false);
}
return true;
}
ZipFileExtensions
,然后继续使用Save方法的异步版本(这次内置到库中) 从性能角度来看,这可能不是最好的解决方案,但从管理的角度来看,您可以将故事分解为#34;将所有内容转换为异步&#34;和#34;通过Ionic.Zlib async&#34;提高应用程序性能,是什么让您的待办事项更精细。
答案 2 :(得分:-1)
public static Task<bool> ZipAndSaveFileAsync(string fileToPack, string archiveName, string outputDirectory)
{
return Task.Run(() =>
{
var archiveNameAndPath = Path.Combine(outputDirectory, archiveName);
using (var zip = new ZipFile())
{
zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
zip.Comment = $"This archive was created at {System.DateTime.UtcNow.ToString("G")} (UTC)";
zip.AddFile(fileToPack);
zip.Save(archiveNameAndPath);
}
return true;
});
}
然后像这样使用
public async Task MyMethod()
{
bool b = await ZipAndSaveFileAsync();
}
答案 3 :(得分:-1)
有些答案表明,压缩文件不是一个异步进行的过程。我不同意这一点。
我可以想象,压缩文件是一个可能需要一些时间的过程。在此期间,您希望保持UI响应,或者您想要同时压缩多个文件,或者您希望上传压缩文件,同时压缩下一个/
您展示的代码是使您的函数异步的正确方法。您怀疑创建这样一个小方法是否有用。为什么不让用户调用Task.Run而不是调用你的异步函数?
其原因称为信息隐藏。通过创建异步功能,您隐藏如何以异步方式压缩,从而使其他人不知道如何执行此操作。
此外,只要你不改变前后条件,信息隐藏就可以自由地改变程序的内部。
其中一个答案说您的功能仍然不是异步的。事实并非如此。您的函数的调用者可以在不等待的情况下调用您的异步函数。当任务是拉链时,调用者可能会做其他事情。只要它需要任务的布尔结果就可以等待任务。
使用示例:
private async Task DoSomethingSimultaneously()
{
var taskZipFileA = ZipAndSaveFileAsync(fileA, ...)
// while this task is zipping do other things,
// for instance start zipping file B:
var taskZipFileB = ZipAndSaveFileAsync(fileB, ...)
// while both tasks are zipping do other things
// after a while you want to wait until both files are finished:
await Task.WhenAll(new Task[] {taskZipFileA, taskZipFileB});
// after the await, the results are known:
if (taskZipFileA.Result)
{
// process the boolean result of taskZipFile A
}
请注意 Task.WaitAll 与 Task.WhenAll 之间的区别 在异步中 - 等待你使用Task.WhenAll。返回是一个任务,所以你可以
await Task.WhenAll (...)
对于正确的async-await,调用任何异步函数的所有函数都需要自己异步并返回Task(而不是void)或Task <TResult
&gt;而不是TResult。有一个例外:事件处理程序可能返回void。
private async void OnButton1_clicked(object sender, ...)
{
bool zipResult = await SaveAndZipFileAsync(...);
ProcessZipResult(zipResult);
}
使用此方法,您的UI会保持响应。您不必调用Task.Run
如果你有一个非异步功能并想在做其他事情时开始压缩,你的非异步功能必须调用Task.Run。由于该函数不是异步,因此无法使用等待。当它需要task.Run的结果时,需要使用Task.Wait或Task.WaitAll
private void NonAsyncZipper()
{
var taskZipFileA = Task.Run ( () => ZipAndSaveFileAsync(...);
// while zipping do other things
// after a while when the result is needed:
taskZipFileA.Wait();
ProcesZipResult(taskZipFileA.Result);
}
答案 4 :(得分:-2)
如果在压缩后可以从Zip库中获取二进制数据,那么使用.NET IO库来保存文件,而不是使用此库来保存文件。
编辑:
对CPU绑定操作(例如压缩)使用async毫无意义。在您的情况下,您可以从异步中获得的唯一好处是将文件保存到磁盘。我认为这就是你所要求的。