如何将WaitAll()转换为异步和等待

时间:2015-09-16 20:09:24

标签: c# multithreading asynchronous async-await c#-5.0

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

using System.Data.SQLite

当我按下面重写时,代码不会阻塞,控制台应用程序在大多数线程完成之前完成。

似乎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
}

是否可以这样做?

WaitAll似乎不等待所有任务完成。我怎么做到这一点?返回类型表示它返回一个任务,但似乎无法弄清楚语法。##标题##

多线程新手,请原谅无知。

2 个答案:

答案 0 :(得分:1)

  

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

是和否。是的,因为你已经做到了。不,因为虽然从功能实施的角度来看是等同的,但从功能调用角度来看,它并不等同(正如您在控制台应用程序中所经历的那样)。与许多其他C#关键字相反,await不是语法糖。编译器强制您使用async标记您的函数以启用await构造是有原因的,原因是现在您的函数不再受阻,并且会给调用者带来额外的责任 - 要么将自己设置为非阻塞(async),要么使用阻塞调用函数。事实上,每个async方法都应该返回TaskTask<TResult>,然后编译器会警告忽略该事实的调用者。唯一的例外是async void,它应该仅用于 用于事件处理程序,它本质上不应该关心被通知的对象在做什么。

很快,async/await不是用于重写同步(阻塞代码),而是为了便于将其转换为异步(非阻塞)。如果你的函数应该是同步的,那么就保持原样(并且你的原始实现完全是这样)。但是,如果您需要异步版本,则应将签名更改为

private async Task PullTablePagesAsync()

使用await重写的正文(您已经正确完成)。为了向后兼容,使用像

这样的新实现提供旧的同步版本
private void PullTablePages() { PullTablePagesAsync().Wait(); }

答案 1 :(得分:1)

  

似乎await语法不像我预期的那样阻塞。

你期待错误的事情。

await语法永远不应该阻止 - 只是在任务完成之前执行流程不应该继续。

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

也许请查看MSDN

上的async / await最佳做法