C# 具有循环的松散顺序并发?
我有以下代码,用于从REST服务获取数据(Get(I)调用),然后用它们的关系填充矩阵(未显示;这发生在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
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
(只要你确保它是线程安全的)。你不应该用答案更新你的问题,而应该发布问题并创建一个编辑标题来指明解决方案,所以其他人可以看到问题是什么,以及它是如何解决的。