异步/等待,多任务(.NET 4.0/NuGet Microsoft异步)

异步/等待,多任务(.NET 4.0/NuGet Microsoft异步),.net,winforms,asynchronous,.net-4.0,async-await,.net,Winforms,Asynchronous,.net 4.0,Async Await,我仅限于Microsoft Async NuGet软件包,到目前为止,我非常喜欢Async/await语法。我有很多方法可以顺利地使用这项技术,但我在尝试变得更花哨一点时遇到了一些问题 我需要加载多个数据源、库存、部门等。我希望顶层方法等待所有数据源加载,然后继续。代码似乎处于死锁状态。我做了一些研究,但在我的理解中遗漏了一些东西 下面是最高层的电话: await GlobalData.WaitAsync(GlobalData.DataType.Inventory | GlobalData.Da

我仅限于Microsoft Async NuGet软件包,到目前为止,我非常喜欢Async/await语法。我有很多方法可以顺利地使用这项技术,但我在尝试变得更花哨一点时遇到了一些问题

我需要加载多个数据源、库存、部门等。我希望顶层方法等待所有数据源加载,然后继续。代码似乎处于死锁状态。我做了一些研究,但在我的理解中遗漏了一些东西

下面是最高层的电话:

await GlobalData.WaitAsync(GlobalData.DataType.Inventory | GlobalData.DataType.Departments).ConfigureAwait(continueOnCapturedContext: false);
WaitAsync

public static async Task<bool> WaitAsync(DataType flags)
{
    TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
    Task<bool> task = tcs.Task;

    ThreadPool.QueueUserWorkItem(_ =>
    {

        try
        {
            List<Task> tasks = new List<Task>();

            foreach (DataType t in Enum.GetValues(typeof(DataType)))
            {
                if (t != DataType.None && flags.HasFlag(t))
                {
                    tasks.Add(GetModel(t).GetTask());
                }
            }

            /* Remove any tasks that are null. */
            tasks.RemoveAll(t => t == null);

            Task.WaitAll(tasks.ToArray());
            tcs.SetResult(true);
        }
        catch (Exception)
        {
            throw;
        }
    });

    return await task;
我可以看到代码的执行情况与预期一样。Task.WaitAll(…)返回并执行tcs.SetResult(true),但决不会使其返回到顶层wait

我能做些什么来解决这个问题


提前谢谢

您不需要使用
TaskCompletionSource
ThreadPool.QueueUserWorkItem
只需
等待任务。所有(tasks.ToArray())
都应该这样做

public static async Task<bool> WaitAsync(DataType flags)
{
    List<Task> tasks = new List<Task>();

    foreach (DataType t in Enum.GetValues(typeof(DataType)))
    {
      if (t != DataType.None && flags.HasFlag(t))
      {
          tasks.Add(GetModel(t).GetTask());
      }
    }

    /* Remove any tasks that are null. */
    tasks.RemoveAll(t => t == null);

    await TaskEx.WhenAll(tasks.ToArray());

    return true;
}
publicstaticasync任务WaitAsync(数据类型标志)
{
列表任务=新列表();
foreach(Enum.GetValues中的数据类型t(typeof(DataType)))
{
如果(t!=DataType.None&&flags.hasglag(t))
{
tasks.Add(GetModel(t).GetTask());
}
}
/*删除任何空的任务*/
tasks.RemoveAll(t=>t==null);
等待TaskEx.WhenAll(tasks.ToArray());
返回true;
}
由于使用了
Task.WaitAll
,很可能发生死锁
Task.WaitAll
Task.Wait
Task.Result
都是阻塞调用,可能导致死锁。有关更多信息,请参阅文章


对于.Net 4.0和异步CTP,您可以使用TaskEx。Whalll

感谢Jon Skeet为我指明了正确的方向。我删除了async/await,并发现以下代码就是解决方案:

public static bool Wait(DataType flags)
{
    List<Task> tasks = new List<Task>();

    foreach (DataType t in Enum.GetValues(typeof(DataType)))
    {
        if (t != DataType.None && flags.HasFlag(t))
        {
            tasks.Add(GetModel(t).GetTask());
        }
    }

    /* Remove any tasks that are null. */
    tasks.RemoveAll(t => t == null);

    Task.WaitAll(tasks.ToArray());

    return true;
}
公共静态bool等待(数据类型标志)
{
列表任务=新列表();
foreach(Enum.GetValues中的数据类型t(typeof(DataType)))
{
如果(t!=DataType.None&&flags.hasglag(t))
{
tasks.Add(GetModel(t).GetTask());
}
}
/*删除任何空的任务*/
tasks.RemoveAll(t=>t==null);
Task.WaitAll(tasks.ToArray());
返回true;
}

为什么您的
WaitAsync
方法是一种异步方法?您可以从同步方法返回
tcs.Task
。。。以
return await…
结尾且没有任何其他
await
表达式的异步方法至少是重构的候选方法。这不是这里的问题,但这是需要思考的问题。(同样,任何时候,只要你有一个catch块,它只是<代码>投掷;,考虑删除它……唯一的好处就是能够在它上加一个断点。”嗨,乔恩,谢谢你的方便反应。您对我使用async/await的观察是正确的。看来我没抓住重点。我将使用TAP模型进行重构,并将aysnc/await仅应用于我的顶级方法。我会发回结果。谢谢很清楚,我不希望它改变行为,只是简化了代码。嗨,任务。WhenAll(…)在使用NuGet Microsoft Async的.NET4.0中不可用。但愿如此!对于.NET4.0和异步CTP,您可以使用
TaskEx.whalll
Oh wow!你是对的。我一定会把它加入我的剧目。很抱歉,我第一次读的时候错过了。正如Jon Skeet所说,我将删除返回等待,因为它不是必需的。此外,我希望代码阻止我的顶级方法。我将使用Jon的Wait和您的WaitAsync。谢谢你,内德!
public static bool Wait(DataType flags)
{
    List<Task> tasks = new List<Task>();

    foreach (DataType t in Enum.GetValues(typeof(DataType)))
    {
        if (t != DataType.None && flags.HasFlag(t))
        {
            tasks.Add(GetModel(t).GetTask());
        }
    }

    /* Remove any tasks that are null. */
    tasks.RemoveAll(t => t == null);

    Task.WaitAll(tasks.ToArray());

    return true;
}