如何实现异步文件Delete/Create/Move?
How to implement an async File.Delete/Create/Move?
因为我必须在我的应用程序中做很多文件 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 的建议改进了代码
- 将 link 添加到 Sriram Sakthivel 提供的原始博客 post
如果你必须这样做,我会这样写方法(注意:我欣然同意这正是 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); });
}
这稍微清理了代码并消除了过多的 context/thread-switching。
在基于 GUI 的程序的上下文中,使用这些包装器似乎没问题。我认为只要您不创建一个具有并行同步和异步 API 的全新库(如参考文章中所述),这并不可怕。
但对我来说,更大的问题是这些操作中的 none 可能需要足够长的时间才能证明首先使它们异步。 IE。您从 UI 线程 Task
中 运行 事情的通常原因是因为您的 UI 线程无法在操作完成时等待。但是在这里,对于这些操作中的每一个,将操作发送到线程池,然后在完成后继续执行的操作,很可能会像操作本身一样增加程序的性能开销。
出于 的原因,我建议完全不要使用这些方法的异步版本。只需直接从 UI 调用 Create()
、Delete()
和 Move()
方法。
(注意:上述情况的一个例外是如果处理网络共享或不同的卷,其中 Move()
涉及实际复制数据。因此即使在那里,它也是一个巨大的 "it depends"。同样,虽然 Delete()
和 Create()
通常即使在网络上也很快,但如果操作实际上会失败,它们可能需要一段时间。您实际上可能有一个很好的用例 运行在那里异步操作)。
因为我必须在我的应用程序中做很多文件 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 的建议改进了代码
- 将 link 添加到 Sriram Sakthivel 提供的原始博客 post
如果你必须这样做,我会这样写方法(注意:我欣然同意这正是 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); });
}
这稍微清理了代码并消除了过多的 context/thread-switching。
在基于 GUI 的程序的上下文中,使用这些包装器似乎没问题。我认为只要您不创建一个具有并行同步和异步 API 的全新库(如参考文章中所述),这并不可怕。
但对我来说,更大的问题是这些操作中的 none 可能需要足够长的时间才能证明首先使它们异步。 IE。您从 UI 线程 Task
中 运行 事情的通常原因是因为您的 UI 线程无法在操作完成时等待。但是在这里,对于这些操作中的每一个,将操作发送到线程池,然后在完成后继续执行的操作,很可能会像操作本身一样增加程序的性能开销。
出于 的原因,我建议完全不要使用这些方法的异步版本。只需直接从 UI 调用 Create()
、Delete()
和 Move()
方法。
(注意:上述情况的一个例外是如果处理网络共享或不同的卷,其中 Move()
涉及实际复制数据。因此即使在那里,它也是一个巨大的 "it depends"。同样,虽然 Delete()
和 Create()
通常即使在网络上也很快,但如果操作实际上会失败,它们可能需要一段时间。您实际上可能有一个很好的用例 运行在那里异步操作)。