uni*_*orn 2 c# linq lambda runtime race-condition
我正在编写一个函数,通过在列表中保留订阅 ID 列表来删除所有订阅。
我遇到了问题
foreach (var subscriptionId in _listOfSubscriptionIds)
{
await _hubProxy.Invoke("removeSubscription", subscriptionId);
_listOfSubscriptionIds.Remove(subscriptionId);
}
Run Code Online (Sandbox Code Playgroud)
因为在 foreach 循环中修改列表会引发错误。我在这个社区上发现我可以这样做,foreach(var subscriptions in _listOfSubscriptionIds.ToList())但这在空间复杂性方面听起来很糟糕,特别是如果有大约 10000000 订阅者。
所以我将其更改为以下内容:
public async Task RemoveSubscription (string subscriptionId)
{
await _hubProxy.Invoke("removeSubscription", subscriptionId);
_listOfSubscriptionIds.Remove(subscriptionId);
}
public void RemoveAllSubscriptions()
{
_listOfSubscriptionIds.ForEach(async subscriptionId => await RemoveSubscription(subscriptionId));
}
Run Code Online (Sandbox Code Playgroud)
一些问题:
我认为第二个在空间和时间复杂度方面更好,但我是对的吗?
在第二种情况下是否存在我可能遗漏的竞争条件?
在RemoveSubscription中,_listOfSubscriptionIds.Remove(subscriptionId)也等待,因为它在异步函数中......?
编辑:我没有分享的一个导致调用_listOfSubscriptionIds.Clear()或迭代出现_listOfSubscriptionIds问题的细节是,可能有多个客户端_hubProxy,每个客户端都有其独特的订阅集。
客户端 1 的 subscriptionIds {a, b, c, d, e}
具有 subIds {f, g, h, I, j, k} 的客户端 2
客户端 3 具有子 ID、{l、m、n、o、p} 等。
这意味着当我调用 client1.RemoveAllSubscriptions() 时,它也可能会清除 client2、client3 等的 subscriptionId。
您的ForEach操作本质上是“一劳永逸”;它不能确保所有任务都能完成。
您可能最好反向使用 for 循环,并保留任务以便可以等待它们:
var tasks = new List<Task>();
for (int i = _listOfSubscriptionIds.Count - 1; i >= 0; i--)
{
tasks.Add(RemoveSubscription(_listOfSubscriptionIds[i]));
}
await Task.WhenAll(tasks);
Run Code Online (Sandbox Code Playgroud)
反向迭代可确保特定索引处的值在循环期间不会更改。
| 归档时间: |
|
| 查看次数: |
2392 次 |
| 最近记录: |