[英]Is there an async version of DirectoryInfo.GetFiles / Directory.GetDirectories in dotNet?
dotNet中是否存在DirectoryInfo.GetFiles / Directory.GetDirectories的異步版本? 我想在F#異步塊中使用它們,並且擁有一個可以使用AsyncCallbacks調用的版本會很好。
問題是我試圖吮吸一堆目錄,可能是在慢速網絡連接上的SMB掛載上,我不希望一堆線程池線程在等待網絡讀取時可能正在做其他工作。
我沒有找到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)
換句話說,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) }
不,我認為沒有。 池線程方法可能是最實用的。 另外,我想你可以下降到的P / Invoke -但是這將是大量的工作。
這可能被認為是一種黑客攻擊,但您可以考慮使用UWP StorageFolder API 。
C#示例(雖然F#可能同樣容易):
using Windows.Storage;
...
var folder = await StorageFolder.GetFolderFromPathAsync(path);
var files = await folder.GetFilesAsync();
var folders = await folder.GetFoldersAsync();
您可以使用Lucian Wischik(Microsoft)的UWP for Desktop庫輕松地從傳統的.NET桌面和控制台應用程序中使用這些內容。
Install-Package UwpDesktop
實際上,根據Directory.GetFiles
的幫助 , Directory.EnumerateFiles
將立即返回第一個結果(它是一個IEnumerable
),而不是在返回之前等待整個列表。 我相信這可能就是你要找的東西。
我已經多次使用這種方法從函數/過程中獲取Async對象,它總是很好用:
let AsyncGetDirectories path =
let fn = new Func<_, _>(System.IO.Directory.GetDirectories)
Async.BuildPrimitive(path, fn.BeginInvoke, fn.EndInvoke)
我不是F#程序員,但我會在C#中這樣做:
static IEnumerable<string> IterateFiles(string path, string pattern) {
var entryQueue = new Queue<string>();
entryQueue.Enqueue(path);
while (entryQueue.Count > 0) {
var subdirs = Directory.GetDirectories(entryQueue.Peek());
var files = Directory.GetFiles(entryQueue.Peek(), pattern, SearchOption.TopDirectoryOnly);
foreach (var file in files)
yield return file;
entryQueue.Dequeue();
foreach(var subdir in subdirs)
entryQueue.Enqueue(subdir);
}
}
我假設在F#中有一個與迭代器類似的構造。
Princess的答案是在任務之間添加粒度的方法 - 所以這種事情會讓其他玩家使用線程池:
let! x = OpenTextAsync("whatever");
// opening for something else to run
let! x = OpenTextAsync("whatever");
// opening for something else to run
let! x = OpenTextAsync("whatever");
當這些阻塞調用中的每一個都很重時,它沒有多大幫助 - 而且基於SMB的GetFiles幾乎就是沉重的定義。
我希望有一些BeginRead
/ EndRead
的目錄,並且GetFiles
/ GetDirectories
只是一個很好的包裝,可以解決暴露一些異步變種的低級調用。 像BeginReadDir
/ EndReadDir
類的東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.