为什么.net中没有异步文件删除?

aep*_*eus 41 .net file-io asynchronous

你有异步版本的读写(开始/结束函数),但没有删除(我可以告诉).这有什么理由吗?是不是有很多理由像读/写一样异步删除?

使用线程来模拟异步行为与异步函数不同.差别很大,确定你得到了感知的并行处理,但它并没有真正阻止阻塞,其他线程仍然被阻止等待文件i/o完成.真正的异步函数(开始/结束函数)在系统级运行,它们排队文件i/o,让应用程序继续运行,并让应用程序知道它何时准备继续执行文件i/o(允许你在等待文件i/o可用时执行其他操作).

usr*_*usr 28

这将是有用的.如果在断开连接的网络共享上删除,则DeleteFile最多可能需要30秒.

原因可能是没有异步删除文件的本机函数.托管API通常是非托管API的包装器.

  • @Legends 是的,那只是一个线程池包装器。这是假异步。JavaScript 语言不支持线程,所以他们必须做这样的事情。其他图书馆也做类似的事情。我认为即使平台支持真正的异步,libuv 也会使所有文件系统 IO 假异步。我可能是错的。 (2认同)

Mic*_*edy 14

这个怎么样:

public static class FileExtensions {
   public static Task DeleteAsync(this FileInfo fi) {
      return Task.Factory.StartNew(() => fi.Delete() );
   }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

FileInfo fi = new FileInfo(fileName);
await fi.DeleteAsync(); // C# 5
fi.DeleteAsync().Wait(); // C# 4
Run Code Online (Sandbox Code Playgroud)

  • 异步的主要原因是不阻止线程(例如,在服务1000个并发请求的Web服务器中).这没有用. (26认同)
  • 再次只是一个很好的线程包装,而不是真正的异步文件i/o. (21认同)
  • @usr你原来的评论写着"这没有用." 它非常有用,因为它根据内核提供的功能实现了异步文件删除的最佳实现.当然,内核空间异步删除甚至会比这更好,但它(尚未)存在. (7认同)
  • 通过该逻辑,您可以通过将其推送到不同的线程来使*any*操作异步,这是真的.这不是特定于文件删除.没有必要提出有关它的问题.事实上OP已经声明他是在真正的异步IO之后(*必须*在内核中处理). (5认同)
  • @usr将文件删除操作委派给异步任务将是异步的,即使文件删除操作尚未完成,也可以将响应发送到客户端.即使操作阻塞线程池线程,此*也是*异步.我同意,如果这个操作在内核中是异步的,就像套接字或文件读取那样会更好*,但在任何一种情况下它都是异步的. (3认同)
  • @aepheus 这是“真正的”异步 I/O,它只是在用户空间而不是内核中完成的。不同之处在于内核中的“重叠”I/O 可以取消(通过`CancelIo`)并且_可能_更有效率。我怀疑这对于像删除文件这样的廉价操作会有很大的不同,这可能是它最初没有在 Win32 中公开的原因。 (2认同)
  • @usr:实际上,大多数删除操作可能相当便宜,因此即使您使用上述代码,默认任务调度程序也不会启动 1000 个线程。但是*如果*您遇到线程问题,您可以改为使用具有很少线程的自定义调度程序(相当简单),或者甚至只是一个`TaskCompletionSource<>`,并发队列仅在一个线程上执行(非常简单)。 (2认同)
  • @usr:实际上,异步的主要原因是不阻塞您的*控制线程*(例如那些负责保持应用程序响应的线程)。 (2认同)
  • @AndréCaron适用于UI应用程序(对于该案例说得很好).对于Web应用程序,这是无关紧要的.如果您有大量的阻塞时间(比如调用慢速服务或休眠),那么可以实现异步. (2认同)

Ale*_*nat 11

所述File类不暴露一个异步文件删除方法; 但是,通过使用FileStream该类,仍然可以利用所提供的 13 个构造函数重载中的一个特定来执行异步文件删除。以下代码将异步删除文件:

using (new FileStream(Path, FileMode.Open, FileAccess.Read, FileShare.None, 1, FileOptions.DeleteOnClose | FileOptions.Asynchronous)) ;
Run Code Online (Sandbox Code Playgroud)

我没有对它进行太多测试,因此您可能需要稍微修改用法。(FileShare.None如果在删除期间不应阻止其他线程访问文件,您可能希望更改为其他内容。)此外,由于此代码不返回 Task 的任何派生,因此使用该Task.Run方法运行它可能是有效的。基本上,它执行的文件删除实际上在 I/O 级别是异步的,因此在这种情况下将其卸载到线程池应该没问题。

  • 在 using 块内,您可以等待 `stream.FlushAsync()` 以强制删除并允许创建异步方法 (2认同)

小智 5

如果没有其他文件打开,则在关闭流时,打开FileStream带有FileOptions.DeleteOnClose将导致Windows删除文件。如果您已经打开a FileStream来进行异步读取/写入,这可能会对您有所帮助,尽管如果您需要等待删除完成也无济于事(尽管根据@JoelFan等待File.Delete完成,并不能保证文件实际上已被删除)。

有趣的是,在针对网络共享进行测试时,似乎像这样打开流而不执行任何操作比()快得多(约40%)File.Delete

using (new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose)) { }
Run Code Online (Sandbox Code Playgroud)