dotNet中是否存在DirectoryInfo.GetFiles/Directory.GetDirectories的异步版本?

Jam*_*ore 40 .net f# asynchronous directoryinfo async-workflow

dotNet中是否存在DirectoryInfo.GetFiles/Directory.GetDirectories的异步版本?我想在F#异步块中使用它们,并且拥有一个可以使用AsyncCallbacks调用的版本会很好.

问题是我试图吮吸一堆目录,可能是在慢速网络连接上的SMB挂载上,我不希望一堆线程池线程在等待网络读取时可能正在做其他工作.

Jul*_*iet 13

我没有找到GetFiles的异步版本,但是如果你查看其他异步操作的源代码,它们的定义如下:

module FileExtensions =

        let UnblockViaNewThread f =
            async { //let ctxt = System.Threading.SynchronizationContext.Current
                    do! Async.SwitchToNewThread ()
                    let res = f()
                    do! Async.SwitchToThreadPool ()
                    //do! Async.SwitchTo ctxt
                    return res }

        type System.IO.File with
            static member AsyncOpenText(path)   = UnblockViaNewThread (fun () -> System.IO.File.OpenText(path))
            static member AsyncAppendText(path) = UnblockViaNewThread (fun () -> System.IO.File.AppendText(path))
            static member AsyncOpenRead(path)   = UnblockViaNewThread (fun () -> System.IO.File.OpenRead(path))
            static member AsyncOpenWrite(path)  = UnblockViaNewThread (fun () -> System.IO.File.OpenWrite(path))
            static member AsyncOpen(path,mode,?access,?share) =
                let access = match access with Some v -> v | None -> System.IO.FileAccess.ReadWrite
                let share = match share with Some v -> v | None -> System.IO.FileShare.None
                UnblockViaNewThread (fun () -> System.IO.File.Open(path,mode,access,share))

            static member OpenTextAsync(path)   = System.IO.File.AsyncOpenText(path)
            static member AppendTextAsync(path) = System.IO.File.AsyncAppendText(path)
            static member OpenReadAsync(path)   = System.IO.File.AsyncOpenRead(path)
            static member OpenWriteAsync(path)  = System.IO.File.AsyncOpenWrite(path)
            static member OpenAsync(path,mode,?access,?share) = System.IO.File.AsyncOpen(path, mode, ?access=access, ?share=share)
Run Code Online (Sandbox Code Playgroud)

换句话说,Async文件,streamreader和WebClient操作只是同步操作的包装器,因此您应该能够在GetFiles/GetDirectories周围编写自己的包装器,如下所示:

module IOExtensions =
    type System.IO.Directory with
        static member AsyncGetFiles(directory) = async { return System.IO.Directory.GetFiles(directory) }
        static member AsyncGetDirectories(path) = async { return System.IO.Directory.GetDirectories(path) }
Run Code Online (Sandbox Code Playgroud)

  • 当然,这不是真正的异步I/O,但它仍然是一个很好的实用解决方案.如果你确实想要真正的异步操作,你必须使用一些可怕的Win32互操作,我认为这在上下文中是不值得的... (4认同)

Mar*_*ell 11

不,我认为没有.池线程方法可能是最实用的.另外,我想你可以下降到的P/Invoke -但是这将是一个很大更多的工作.

  • 现在仍然如此,.NET 4.5出现了一堆新的异步API吗?我一直在寻找这个并没有看到它. (6认同)
  • 从 .NET Core 2.2 开始仍然如此。 (3认同)
  • “或者,我想你可以下拉到 P/Invoke” - 我看不到任何用于文件系统操作的 Win32 Overlapped IO 或本机 Win32 异步 API,所以我不确定 P/Invoke 在这里有何帮助。据我所知,UWP 中的异步文件系统 API 也在内部使用线程,而不是实际重叠 IO 或 IO 中断驱动。 (2认同)

Mat*_*int 6

这可能被认为是一种黑客攻击,但您可以考虑使用UWP StorageFolder API.

C#示例(尽管F#可能同样简单):

using Windows.Storage;

...

var folder = await StorageFolder.GetFolderFromPathAsync(path);
var files = await folder.GetFilesAsync();
var folders = await folder.GetFoldersAsync();
Run Code Online (Sandbox Code Playgroud)

您可以使用Lucian Wischik(Microsoft)的UWP for Desktop库轻松地从传统的.NET桌面和控制台应用程序中使用这些内容.

Install-Package UwpDesktop
Run Code Online (Sandbox Code Playgroud)

  • 在内部,此库使用什么API?它是否调用* true * -async(重叠的IO?)Win32函数,还是仅将所有内容包装在线程中? (2认同)

mos*_*ald 5

实际上,根据 的帮助Directory.GetFilesDirectory.EnumerateFiles将立即返回第一个结果(它是一个IEnumerable),而不是在返回之前等待整个列表。我相信这可能就是您正在寻找的。

  • 并不真地。即使返回第一个文件也可能需要数十或数百毫秒(想想 UNC 路径)。在这段时间里你的执行线程都被阻塞。 (10认同)