C# 如何将WaitAll()转换为async并等待

C# 如何将WaitAll()转换为async并等待,c#,multithreading,asynchronous,async-await,c#-5.0,C#,Multithreading,Asynchronous,Async Await,C# 5.0,是否可以使用async await语法重写下面的代码 private void PullTablePages() { var taskList = new List<Task>(); var faultedList = new List<Task>(); foreach (var featureItem in featuresWithDataName) { var task = Task.Run(() => Pull

是否可以使用async await语法重写下面的代码

private void PullTablePages()
{
    var taskList = new List<Task>();
    var faultedList = new List<Task>();

    foreach (var featureItem in featuresWithDataName)
    {
        var task = Task.Run(() => PullTablePage();
        taskList.Add(task);

        if(taskList.Count == Constants.THREADS)
        {
            var index = Task.WaitAny(taskList.ToArray());
            taskList.Remove(taskList[index]);
        }
    }

    if (taskList.Any())
    {
        Task.WaitAll(taskList.ToArray());
    }

    //todo: do something with faulted list
}
private void PullTablePages()
{
var taskList=新列表();
var faultedList=新列表();
foreach(featuresWithDataName中的var featureItem)
{
var task=task.Run(()=>PullTablePage();
任务列表。添加(任务);
if(taskList.Count==Constants.THREADS)
{
var index=Task.WaitAny(taskList.ToArray());
删除(任务列表[索引]);
}
}
if(taskList.Any())
{
Task.WaitAll(taskList.ToArray());
}
//todo:对故障列表执行某些操作
}
当我像下面那样重写它时,代码不会阻塞,控制台应用程序在大多数线程完成之前就完成了

似乎等待语法没有像我预期的那样阻塞

private async void PullTablePagesAsync()
{
    var taskList = new List<Task>();
    var faultedList = new List<Task>();

    foreach (var featureItem in featuresWithDataName)
    {
        var task = Task.Run(() => PullTablePage();

        taskList.Add(task);

        if(taskList.Count == Constants.THREADS)
        {
            var anyFinished = await Task.WhenAny(taskList.ToArray());

            await anyFinished;

            for (var index = taskList.Count - 1; index >= 0; index--)
            {
               if (taskList[index].IsCompleted)
               {
                  taskList.Remove(taskList[index]);
               }
            }        
        }
    }

    if (taskList.Any())
    {
       await Task.WhenAll(taskList);
    }

    //todo: what to do with faulted list?
}
private异步void PullTablePagesAsync()
{
var taskList=新列表();
var faultedList=新列表();
foreach(featuresWithDataName中的var featureItem)
{
var task=task.Run(()=>PullTablePage();
任务列表。添加(任务);
if(taskList.Count==Constants.THREADS)
{
var anyFinished=wait Task.WhenAny(taskList.ToArray());
等待一切完成;
对于(var index=taskList.Count-1;index>=0;index--)
{
if(任务列表[索引].IsCompleted)
{
删除(任务列表[索引]);
}
}        
}
}
if(taskList.Any())
{
等待任务。WhenAll(任务列表);
}
//todo:如何处理故障列表?
}
有可能吗

WaitAll似乎不会等待所有任务完成。如何让它完成?返回类型表示它返回任务,但似乎无法理解语法。##Heading##

多线程新手,请原谅无知

是否可以使用async await语法重写下面的代码

private void PullTablePages()
{
    var taskList = new List<Task>();
    var faultedList = new List<Task>();

    foreach (var featureItem in featuresWithDataName)
    {
        var task = Task.Run(() => PullTablePage();
        taskList.Add(task);

        if(taskList.Count == Constants.THREADS)
        {
            var index = Task.WaitAny(taskList.ToArray());
            taskList.Remove(taskList[index]);
        }
    }

    if (taskList.Any())
    {
        Task.WaitAll(taskList.ToArray());
    }

    //todo: do something with faulted list
}
是和否。是,因为您已经这样做了。不是,因为从函数实现的角度来看,它是等效的,但从函数调用方的角度来看,它是不等效的(正如您在控制台应用程序中已经体验到的).与许多其他C#关键字相反,
await
不是语法糖。编译器强制您使用
async
标记函数以启用
await
构造是有原因的,原因是现在您的函数不再阻塞,这给调用方带来了额外的责任-或者put它们本身是非阻塞的(
async
)或者对函数使用阻塞调用。每个
async
方法实际上是并且应该返回
Task
Task
,然后编译器将警告忽略该事实的调用方。唯一的例外是
async void
,它应该只用于事件处理程序,本质上应该是不管被通知的对象在做什么

简而言之,
async/await
不是为了重写同步(阻塞代码),而是为了方便地将其转换为异步(非阻塞)。如果您的函数应该是同步的,那么只需保持它的原样(您最初的实现正完美地做到这一点)。但如果您需要异步版本,则应将签名更改为

private async Task PullTablePagesAsync()
使用
wait
rewrited body(您已经正确执行了)。为了向后兼容,请使用如下新实现提供旧的同步版本

private void PullTablePages() { PullTablePagesAsync().Wait(); }
似乎等待语法没有像我预期的那样阻塞

private async void PullTablePagesAsync()
{
    var taskList = new List<Task>();
    var faultedList = new List<Task>();

    foreach (var featureItem in featuresWithDataName)
    {
        var task = Task.Run(() => PullTablePage();

        taskList.Add(task);

        if(taskList.Count == Constants.THREADS)
        {
            var anyFinished = await Task.WhenAny(taskList.ToArray());

            await anyFinished;

            for (var index = taskList.Count - 1; index >= 0; index--)
            {
               if (taskList[index].IsCompleted)
               {
                  taskList.Remove(taskList[index]);
               }
            }        
        }
    }

    if (taskList.Any())
    {
       await Task.WhenAll(taskList);
    }

    //todo: what to do with faulted list?
}
你的期望是错误的

await
语法不应该阻塞-只是在任务完成之前执行流不应该继续

通常,在返回任务的方法中使用async/await。在这种情况下,在返回类型为void的方法中使用async/await。 了解异步void方法需要时间,这就是为什么通常不鼓励使用异步void方法。异步void方法与调用方法同步(块)运行,直到等待第一个(未完成)任务。之后发生的情况取决于执行上下文(通常在池上运行)。重要的是:调用方法(调用
PullTablePAgesAsync
)的程序不知道连续性,也不知道
PullTablePAgesAsync
中的所有代码何时完成


也许可以查看一下上的async/await最佳实践,将
PullTablePagesAsync
的返回类型更改为
Task
,然后在主函数/循环中等待它。您实际上想在这里做什么?您的代码目前没有多大意义。运行一个任务列表。如果其中一个任务完成,请启动另一个任务,直到所有任务都完成,然后执行respect一次最多4个async/await不用于重写阻塞代码。事实上,它们是专门为非阻塞而设计的。这个问题没有任何意义。
async void
只是为了与事件兼容。If
PullTablePagesAsync
不是事件处理程序(它看起来不像一个)您不应该使用
async void
。请参阅“”,我似乎错误地认为我可以轻松地阻止/等待问题中的async wait构造