我有一種方法,我需要遞回來從 API(圖形)獲取檔案和檔案夾的層次結構。當我在 for 回圈中進行遞回時,它按預期作業并回傳包含 665 個檔案的層次結構。這需要大約一分鐘,因為它一次只獲取一個檔案夾,而使用 Task.WhenAll 只需要 10 秒。
當使用 Task.WhenAll 我得到不一致的結果時,它會根據運行回傳包含 661 到 665 個檔案的層次結構,并使用完全相同的代碼。我使用變數 totalFileCount 作為它找到多少檔案的指示。
顯然我做錯了什么,但我無法弄清楚是什么。任何幫助是極大的贊賞!
回圈
for (int i = 0; i < folders.Count; i )
{
var folder = folders[i];
await GetSharePointHierarchy(folder, folderItem, $"{outPath}{folder.Name}\\");
}

任務.WhenAll
var tasks = new List<Task>();
for (int i = 0; i < folders.Count; i )
{
var folder = folders[i];
var task = GetSharePointHierarchy(folder, folderItem, $"{outPath}{folder.Name}\\");
tasks.Add(task);
}
await Task.WhenAll(tasks);

完整方法
public async Task<GraphFolderItem> GetSharePointHierarchy(DriveItem currentDrive, GraphFolderItem parentFolderItem, string outPath = "")
{
IEnumerable<DriveItem> children = await graphHandler.GetFolderChildren(sourceSharepointId, currentDrive.Id);
var folders = new List<DriveItem>();
var files = new List<DriveItem>();
var graphFolderItems = new List<GraphFolderItem>();
foreach (var item in children)
{
if (item.Folder != null)
{
System.IO.Directory.CreateDirectory(outPath item.Name);
//Console.WriteLine(outPath item.Name);
folders.Add(item);
}
else
{
totalFileCount ;
files.Add(item);
}
}
var folderItem = new GraphFolderItem
{
SourceFolder = currentDrive,
ItemChildren = files,
FolderChildren = graphFolderItems,
DownloadPath = outPath
};
parentFolderItem.FolderChildren.Add(folderItem);
for (int i = 0; i < folders.Count; i )
{
var folder = folders[i];
await GetSharePointHierarchy(folder, folderItem, $"{outPath}{folder.Name}\\");
}
return parentFolderItem;
}
uj5u.com熱心網友回復:
這是比賽條件問題。在并行執行中,您不應使用普通資料型別或變數。您應該始終根據您的要求使用執行緒安全概念,例如執行緒安全資料型別/集合 或鎖或監視器或互鎖。
在這種情況下, interlocked.Increment 是一種很好的方法,例如替換下面使用的方法totalFileCount
Interlocked.Increment(ref totalFileCount);
請參考以下鏈接以獲得良好的理解
詳細的執行緒安全概念或執行緒安全
uj5u.com熱心網友回復:
似乎問題在于,當您使用Task.WhenAll方式時,您正在使代碼流并行運行,而在每次運行異步函式時使用await的另一種方式,代碼流實際上并沒有并行運行
這正是你的問題,你的源代碼里面的異步函式訪問共享記憶體物件 - totalFileCount 是什么導致多執行緒同時訪問一個物件。
為了修復它并仍然并行執行代碼,請使用鎖定陳述句圍繞對 totalFileCount 實體的訪問,該陳述句限制代碼塊的并發執行次數
lock(lockRefObject)
{
totalFileCount ;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/515672.html
標籤:C#多线程异步递归
下一篇:回傳具有隨機X值的陣列的遞回函式
