C# 具有循环的松散顺序并发?

C# 具有循环的松散顺序并发?,c#,.net,concurrency,windows-runtime,async-await,C#,.net,Concurrency,Windows Runtime,Async Await,我有以下代码,用于从REST服务获取数据(Get(I)调用),然后用它们的关系填充矩阵(未显示;这发生在addLabels())中 所有的Get()调用都可以彼此并行运行,但它们必须在任何东西进入第二个循环之前全部完成(在第二个循环中,调用可以彼此并行运行)。addLabel()调用取决于要完成的Get()调用的工作量 **对于任何在这篇文章中遇到障碍的人,以下代码就是解决方案:** private async void GetTypeButton_Click(object sender, Ro

我有以下代码,用于从REST服务获取数据(Get(I)调用),然后用它们的关系填充矩阵(未显示;这发生在
addLabels()
)中

所有的
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);
private async void GetTypeButton\u单击(对象发送方,RoutedEventArgs e)
{
wait PokeType.InitTypes();//初始化矩阵中的关系
var table=PokeType.effectiveness矩阵;
//漂亮的打印表格
// ...
// ...
}
私有静态bool initialized=false;
公共静态异步任务InitTypes()
{
如果(初始化)返回;
//等待试块,直到第一批完成
wait Task.WhenAll(Enumerable.Range(1,NUM_TYPES/*inclusive*/).Select(i=>Get(i));
//不需要并行化,因为它的工作速度很快。
foreach(cachedTypes.Values中的PokeType类型)
{
JObject data=type.GetJsonFromCache();
添加标签(类型,(JArray)数据[“超级有效”],有效性。超级有效性针对);
添加标签(类型,(JArray)数据[“无效”]、有效性。不完全有效);
添加标签(类型,(JArray)数据[“无影响”],有效性。UselessAgainst);
}
初始化=真;
}
公共静态异步任务Get(int-id);
当前编写代码时,
InitTypes()
方法尝试同时进入两个循环;
cachedTypes
字典为空,因为第一个循环尚未完成填充,因此它从未运行,也未构建任何关系


如何正确构造此函数?谢谢

并行和异步等待不能很好地结合在一起。您的异步lambda表达式实际上是
async void
,因为
是并行的。For
排除了
操作
,这意味着
是并行的。For
不能等待该操作完成

如果您试图同时多次调用
Get(i)
,并等待它们完成后再继续,则需要使用
任务。所有

await Task.WhenAll(Enumerable.Range(1, NUM_TYPES).Select(() => Get(i)))

此外,还存在争议的是
Parallel.ForEach()
循环是否首先应该是并行的
addLabels()
可能是线程安全的,也可能不是线程安全的,但即使是线程安全的,那里的计算速度是否真的足够慢,足以证明使用
并行
而不仅仅是简单的
foreach
语句的开销是合理的?@i3arnon原谅以前没有使用过它的人;我知道这是如何代替标准for循环的,但我如何(干净地)使用它来替换for each?@PeterDuniho没有意识到Parallel.ForEach的开销很大。他们只是在做JSON解析,所以我可能可以同步地做这些。一个标准的foreach就可以了,因为前面的循环正在等待中,对吗?@Benjin是的。由于它是同步的,如果你想将其并行化,你可以使用
Parallel
Task.Run
(只要你确保它是线程安全的)。你不应该用答案更新你的问题,而应该发布问题并创建一个编辑标题来指明解决方案,所以其他人可以看到问题是什么,以及它是如何解决的。