我有以下代码用于从REST服务(Get(i)
调用)获取数据,然后使用它们的关系填充矩阵(未显示;这在addLabels()
内发生)。 / p>
所有Get()
调用都可以相互并行运行,但必须在任何进入第二个循环之前完成所有调用(其中,调用可以再次并行运行)。 addLabel()
来电取决于Get()
来电完成的工作。
**对于任何绊倒这篇文章的人来说,这段代码就是解决方案:**
private async void GetTypeButton_Click(object sender, RoutedEventArgs e)
{
await PokeType.InitTypes(); // initializes relationships in the matrix
var table = PokeType.EffectivenessMatrix;
// pretty-printing the table
// ...
// ...
}
private static bool initialized = false;
public static async Task InitTypes()
{
if (initialized) return;
// await blocks until first batch is finished
await Task.WhenAll(Enumerable.Range(1, NUM_TYPES /* inclusive */).Select(i => Get(i)));
// doesn't need to be parallelized because it's quick work.
foreach(PokeType type in cachedTypes.Values)
{
JObject data = type.GetJsonFromCache();
addLabels(type, (JArray)data["super_effective"], Effectiveness.SuperEffectiveAgainst);
addLabels(type, (JArray)data["ineffective"], Effectiveness.NotVeryEffectiveAgainst);
addLabels(type, (JArray)data["no_effect"], Effectiveness.UselessAgainst);
}
initialized = true;
}
public static async Task<PokeType> Get(int id);
当前编写代码时,InitTypes()
方法会尝试同时进入两个循环; cachedTypes
字典是空的,因为第一个循环还没有完成填充它,所以它永远不会运行,也没有构建关系。
如何正确构建此功能?谢谢!
答案 0 :(得分:1)
并行和async-await
不能很好地融合在一起。您的异步lambda表达式实际上是async void
,因为Parallel.For
会感谢Action<int>
,这意味着Parallel.For
无法等待该操作完成。
如果您尝试多次同时致电Get(i)
并等待它们完成,请继续使用Task.WhenAll
:
await Task.WhenAll(Enumerable.Range(1, NUM_TYPES).Select(() => Get(i)))