如何实现异步File.Delete / Create / Move?

时间:2015-03-12 15:32:58

标签: c# asynchronous io task-parallel-library async-await

由于我必须在我的应用程序中执行大量文件I / O操作, 我决定异步实现它们。 查看MSDN,File.Create,File.Delete和File.Move没有异步对应项。据我所知,原因是不存在用于文件删除,创建或移动的异步Win32实现,所以我最终得到了以下解决方案:

public static Task DeleteAsync(string path)
{
     Guard.FileExists(path);

     return Task.Run(() => File.Delete(path));
}

public static Task<FileStream> CreateAsync(string path)
{
     Guard.IsNotNullOrWhitespace(path);

     return Task.Run(() => File.Create(path));
}

public static Task MoveAsync(string sourceFileName, string destFileName)
{
     Guard.FileExists(sourceFileName);
     Guard.IsNotNullOrWhitespace(destFileName);

     return Task.Run(() => { File.Move(sourceFileName, destFileName); });
}

考虑到范式"Don’t use Task.Run in Libraries",我想知道是否有更好的实现,还是应该回退到同步代码?

非常感谢提前!

编辑:


  • 根据Peter Duniho推荐
  • 改进了代码
  • 添加了由Sriram Sakthivel提供的原始博文的链接

1 个答案:

答案 0 :(得分:9)

如果你必须这样做,我会写这样的方法(注意:我很同意这正是Stephens Cleary和Toub敦促我们不要做的事情):

public static Task DeleteAsync(string path)
{
     Guard.FileExists(path);

     return Task.Run(() => { File.Delete(path); });
}

public static Task<FileStream> CreateAsync(string path)
{
     Guard.IsNotNullOrWhitespace(path);

     return Task.Run(() => File.Create(path));
}

public static Task MoveAsync(string sourceFileName, string destFileName)
{
     Guard.FileExists(sourceFileName);
     Guard.IsNotNullOrWhitespace(destFileName);

     return Task.Run(() => { File.Move(sourceFileName, destFileName); });
}

这会稍微清理代码并消除过多的上下文/线程切换。

在基于GUI的程序环境中,使用这样的包装器似乎很好。我认为只要您不创建一个并行的同步和异步API的全新库,如所提到的文章所述,这并不可怕。

但对我来说,更大的问题是这些操作中没有一个可能花费足够长的时间来证明它们首先使它们异步。即从UI线程在Task中运行事物的通常原因是因为您的UI线程在操作完成时无法等待。但是在这里,对于这些操作中的每一个,将操作发送到线程池,然后在完成后继续操作,可能会为操作本身添加尽可能多的性能开销。

这是 的原因,我建议不要打扰这些方法的异步版本。只需直接通过用户界面调用Create()Delete()Move()方法。

(注意:上面的一个例外是如果处理网络共享或不同的卷,其中Move()涉及实际复制数据。所以即使在那里,它也是一个巨大的“它依赖”。同样, Delete()Create()通常在网络上通常很快,如果操作实际上会失败,它们可能需要一段时间。实际上,你可能有一个很好的用例来异步运行操作。)< / p>