C# 异步等待-需要一些指导吗
我尝试了许多不同的方法来实现这一点,我确信这不是连接多线程的async/Wait的正确方法。这是我到目前为止所拥有的。这是一个我试图使之异步的目录遍历器。我知道您没有看到任何async或Wait关键字,这是因为我没有成功,但这就是我正在尝试做的。现在它运行在一个控制台应用程序中,但我将在以后得到一个工作的POC后进行抽象和重构。感谢您的指导C# 异步等待-需要一些指导吗,c#,multithreading,async-await,task,directory-walk,C#,Multithreading,Async Await,Task,Directory Walk,我尝试了许多不同的方法来实现这一点,我确信这不是连接多线程的async/Wait的正确方法。这是我到目前为止所拥有的。这是一个我试图使之异步的目录遍历器。我知道您没有看到任何async或Wait关键字,这是因为我没有成功,但这就是我正在尝试做的。现在它运行在一个控制台应用程序中,但我将在以后得到一个工作的POC后进行抽象和重构。感谢您的指导 static void RunProgram(CancellationToken ct) { try {
static void RunProgram(CancellationToken ct)
{
try
{
foreach (var dir in _directoriesToProcess)
{
var newTask = CreateNewTask(dir, ct);
_tasks.Add(newTask);
}
while (_tasks.Count > 0)
{
lock (_collectionLock)
{
var t = _tasks.Where(x => x.IsCompleted == true).ToList();
if (t != null)
foreach (var task in t)
{
_tasks.Remove(task);
}
}
}
OutputFiles();
StopAndCleanup();
}
catch (Exception ex)
{
Log(LogColor.Red, "Error: " + ex.Message, false);
_cts.Cancel();
}
}
static Task CreateNewTask(string Path, CancellationToken ct)
{
return Task.Factory.StartNew(() => GetDirectoryFiles(Path, ct), ct);
}
static void GetDirectoryFiles(string Path, CancellationToken ct)
{
if (!ct.IsCancellationRequested)
{
List<string> subDirs = new List<string>();
int currentFileCount = 0;
try
{
currentFileCount = Directory.GetFiles(Path, _fileExtension).Count();
subDirs = Directory.GetDirectories(Path).ToList();
lock (_objLock)
{
_overallFileCount += currentFileCount;
Log(LogColor.White, "- Current path: " + Path);
Log(LogColor.Yellow, "-- Sub directory count: " + subDirs.Count);
Log(LogColor.Yellow, "-- File extension: " + _fileExtension);
Log(LogColor.Yellow, "-- Current count: " + currentFileCount);
Log(LogColor.Red, "-- Running total: " + _overallFileCount);
_csvBuilder.Add(string.Format("{0},{1},{2},{3}", Path, subDirs.Count, _fileExtension, currentFileCount));
Console.Clear();
Log(LogColor.White, "Running file count: " + _overallFileCount, false, true);
}
foreach (var dir in subDirs)
{
lock (_collectionLock)
{
var newTask = CreateNewTask(dir, ct);
_tasks.Add(newTask);
}
}
}
catch (Exception ex)
{
Log(LogColor.Red, "Error: " + ex.Message, false);
_cts.Cancel();
}
}
}
静态无效运行程序(CancellationToken ct)
{
尝试
{
foreach(var dir in_directoriesToProcess)
{
var newTask=CreateNewTask(dir,ct);
_任务。添加(newTask);
}
而(_tasks.Count>0)
{
锁(收集锁)
{
var t=_tasks.Where(x=>x.IsCompleted==true).ToList();
如果(t!=null)
foreach(t中的var任务)
{
_任务。删除(任务);
}
}
}
OutputFiles();
stop和cleanup();
}
捕获(例外情况除外)
{
日志(LogColor.Red,“错误:+ex.消息,错误);
_cts.Cancel();
}
}
静态任务CreateNewTask(字符串路径,CancellationToken ct)
{
返回Task.Factory.StartNew(()=>GetDirectoryFiles(Path,ct),ct);
}
静态无效GetDirectoryFiles(字符串路径,CancellationToken ct)
{
如果(!ct.iscancellationrequest)
{
列表细分=新列表();
int currentFileCount=0;
尝试
{
currentFileCount=目录.GetFiles(路径,_fileExtension).Count();
subDirs=Directory.GetDirectories(Path.ToList();
锁(_objLock)
{
_总体文件计数+=当前文件计数;
日志(LogColor.White,“-当前路径:”+路径);
日志(LogColor.Yellow,“--子目录计数:”+子目录计数);
日志(LogColor.Yellow,“--文件扩展名:”+\u文件扩展名);
日志(LogColor.Yellow,“--当前计数:”+currentFileCount);
日志(LogColor.Red,“--运行总数:”+_总文件数);
_添加(string.Format(“{0},{1},{2},{3}”,路径,subders.Count,_fileExtension,currentFileCount));
Console.Clear();
日志(LogColor.White,“正在运行的文件计数:”+_总体文件计数,false,true);
}
foreach(子目录中的var dir)
{
锁(收集锁)
{
var newTask=CreateNewTask(dir,ct);
_任务。添加(newTask);
}
}
}
捕获(例外情况除外)
{
日志(LogColor.Red,“错误:+ex.消息,错误);
_cts.Cancel();
}
}
}
您可以使用任务异步运行同步代码。运行(()=>{//code})代码>
还可以将返回类型更改为Task
,以便等待它
我会将您的代码重写如下:
static void RunProgram(CancellationToken ct)
{
try
{
foreach (var dir in _directoriesToProcess)
{
var newTask = CreateNewTask(dir, ct);
_tasks.Add(newTask);
}
//change your while so it does not execute all the time
while (_tasks.Count > 0)
{
lock (_collectionLock)
{
var tsk = _tasks.FirstOrDefault();
if (tsk != null)
{
if (tsk.Status <= TaskStatus.Running)
await tsk;
_tasks.Remove(tsk);
}
}
}
OutputFiles();
StopAndCleanup();
}
catch (Exception ex)
{
Log(LogColor.Red, "Error: " + ex.Message, false);
_cts.Cancel();
}
}
static Task CreateNewTask(string Path, CancellationToken ct)
{
return Task.Factory.StartNew(() => GetDirectoryFiles(Path, ct), ct);
}
//always use Task (or Task<T>) as return so you can await the process
static async Task GetDirectoryFiles(string Path, CancellationToken ct)
{
if (!ct.IsCancellationRequested)
{
//Insert Magic
await Task.Run(() => {
List<string> subDirs = new List<string>();
int currentFileCount = 0;
try
{
currentFileCount = Directory.GetFiles(Path, _fileExtension).Count();
subDirs = Directory.GetDirectories(Path).ToList();
lock (_objLock)
{
_overallFileCount += currentFileCount;
Log(LogColor.White, "- Current path: " + Path);
Log(LogColor.Yellow, "-- Sub directory count: " + subDirs.Count);
Log(LogColor.Yellow, "-- File extension: " + _fileExtension);
Log(LogColor.Yellow, "-- Current count: " + currentFileCount);
Log(LogColor.Red, "-- Running total: " + _overallFileCount);
_csvBuilder.Add(string.Format("{0},{1},{2},{3}", Path, subDirs.Count, _fileExtension, currentFileCount));
Console.Clear();
Log(LogColor.White, "Running file count: " + _overallFileCount, false, true);
}
foreach (var dir in subDirs)
{
lock (_collectionLock)
{
var newTask = CreateNewTask(dir, ct);
_tasks.Add(newTask);
}
}
});
}
catch (Exception ex)
{
Log(LogColor.Red, "Error: " + ex.Message, false);
_cts.Cancel();
}
}
}
静态无效运行程序(CancellationToken ct)
{
尝试
{
foreach(var dir in_directoriesToProcess)
{
var newTask=CreateNewTask(dir,ct);
_任务。添加(newTask);
}
//更改您的while,使其不会一直执行
而(_tasks.Count>0)
{
锁(收集锁)
{
var tsk=_tasks.FirstOrDefault();
如果(tsk!=null)
{
if(tsk.Status GetDirectoryFiles(Path,ct),ct);
}
//始终使用Task(或Task)作为返回,以便您可以等待流程
静态异步任务GetDirectoryFiles(字符串路径,CancellationToken ct)
{
如果(!ct.iscancellationrequest)
{
//插入魔法
等待任务。运行(()=>{
列表细分=新列表();
int currentFileCount=0;
尝试
{
currentFileCount=目录.GetFiles(路径,_fileExtension).Count();
subDirs=Directory.GetDirectories(Path.ToList();
锁(_objLock)
{
_总体文件计数+=当前文件计数;
日志(LogColor.White,“-当前路径:”+路径);
日志(LogColor.Yellow,“--子目录计数:”+子目录计数);
日志(LogColor.Yellow,“--文件扩展名:”+\u文件扩展名);
日志(LogColor.Yellow,“--当前计数:”+currentFileCount);
日志(LogColor.Red,“--运行总数:”+_总文件数);
_添加(string.Format(“{0},{1},{2},{3}”,路径,subders.Count,_fileExtension,currentFileCount));
Console.Clear();
日志(LogColor.White,“正在运行的文件计数:”+_总体文件计数,false,true);
}
foreach(子目录中的var dir)
{
锁(收集锁)
{
var newTask=CreateNewTask(dir,ct);
_任务。添加(newTask);
}
}
});
}
捕获(例外情况除外)
{
日志(LogColor.Red,“错误:+ex.消息,错误);
_cts.Cancel();
}
}
}
我认为您尝试执行的操作没有任何问题,只是要小心不受控制的并发性,例如,在不同线程上同时读取太多目录。上下文切换可能会导致速度变慢
而不是像做副业那样做
static async Task<IEnumerable<DirectoryStat>> GetDirectoryFiles(string path, string fileExtension, CancellationToken ct)
{
var thisDirectory = await Task.Run(() => /* Get directory file count and return a DirectoryStat object */);
var subDirectoriesResults = await Task.WhenAll(Directory.GetDirectories(path).Select(dir => GetDirectoryFiles(dir, fileExtension, ct)));
return (new[] { thisDirectory }).Concat(subDirectoryResults);
}