【发布时间】:2020-03-14 04:41:46
【问题描述】:
下面有一个方法可以将 id 映射到 MyRecord 的集合到字典中。
Dictionary 值由于 Select.
此方法调用的结果在其他地方用作异步环境中的线程安全变量。
该类的调用者检索给定 id 的记录列表并将其具体化。
_cache = await BuildCache();
var list = _cache[id].ToList();
如果两个线程同时实现一个值会怎样?
T1:_cache[123].ToList();
T2:_cache[123].ToList();
private async Task<IDictionary<int, IEnumerable<MyRecord>> BuildCache()
{
var records = await _repo.GetAll();
return BuildMap(records);
}
private IDictionary<int, IEnumerable<MyRecord>> BuildMap(IEnumerable<MyRecord> records)
{
var internStrings = new HashSet<string>();
var map = records?
.GroupBy(x => x.PersonId)
.ToDictionary((k) => k.Key, (v) => v.Select(t =>
{
if (internStrings.TryGetValue(t.Title, out string interned))
t.Title= interned;
else
internStrings.Add(t.Title);
return t;
}));
return map;
}
我问的原因是因为hashSet在从internStrings.Add(t.Title)调整大小时抛出错误,
当多个线程具体化时,惰性求值是否会自行跳闸?
*这是例外:
System.ArgumentException: Destination array was not long enough. Check the destination index, length, and the array's lower bounds.
at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable)
at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length)
at System.Collections.Generic.HashSet`1.SetCapacity(Int32 newSize)
at System.Collections.Generic.HashSet`1.IncreaseCapacity()
at System.Collections.Generic.HashSet`1.AddIfNotPresent(T value)
注意:底层 IEnumerable 来自一个小巧的查询而不是 EF,我不是在询问 LINQ to SQL
connection.QueryAsync<MyRecord>(SqlQueries.MyQuery, commandTimeout: _commandTimeout))
【问题讨论】:
-
你确定这可以编译吗?你的
BuildMap方法不是异步的, -
抛出异常的那一行是什么?
-
@this 是伪代码,但我将 await 移至 repo 调用
-
@fabio 异常来自
internStrings.Add(t.Title); -
@Smolakian 这是个例外:
System.ArgumentException: Destination array was not long enough. Check the destination index, length, and the array's lower bounds.