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

时间:2014-08-14 06:19:28

标签: .net winforms asynchronous .net-4.0 async-await

我仅限于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;

最后,在GetTask(..)

public override Task GetTask()
{
    /* If the task is not null, another caller has asked for the data already, hook into the callback. */
    if (m_LoadingTask != null)
    {
        return m_LoadingTask;
    }
    else
    {
        /* Only load if the bindingList is null, return the Task. */
        if (m_Data == null)
        {
            return this.LoadAsync();
        }
    }

    return null;
}

我可以按预期看到执行代码的执行情况。 Task.WaitAll(...)返回并执行tcs.SetResult(true),但永远不会让它回到顶层等待。

我该怎么做才能解决这个问题?

提前致谢。

2 个答案:

答案 0 :(得分:2)

您无需使用TaskCompletionSourceThreadPool.QueueUserWorkItem只需await Task.WhenAll(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;
}

因为您使用了Task.WaitAll,所以会发生死锁。 Task.WaitAllTask.WaitTask.Result阻止了调用,可能导致死锁。有关详细信息,请参阅this文章。

对于.Net 4.0和Async CTP,您可以使用TaskEx.WhenAll

答案 1 :(得分:0)

感谢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;
}