我仅限于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),但永远不会让它回到顶层等待。
我该怎么做才能解决这个问题?
提前致谢。
答案 0 :(得分:2)
您无需使用TaskCompletionSource
或ThreadPool.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.WaitAll
,Task.Wait
和Task.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;
}