我正在寻找一种方法来协调来自3个不同来源的元素。我已将元素简化为只有一个键(字符串)和版本(长)。
同时获得列表(2个来自单独的数据库查询,1个来自另一个系统上的内存缓存)。
对于我的最终结果,我只关心所有3个来源中不是相同版本的元素。所以我关心的结果将是一个键列表,每个系统中都有相应的版本。
Element1 | system1:v100 | system2:v100 | system3:v101 |
Element2 | system1:missing | system2:v200 | system3:v200 |
可以丢弃具有相同版本的元素。
实现这个想法的两种方法是
等待所有数据源完成检索,然后遍历每个列表以聚合具有密钥联合+所有3个版本的主列表(丢弃所有相同的项目)。
一旦检索完第一个列表,就将其放入并发集合(如字典(在.net 4.0中提供))中,并在它们出现时立即开始聚合剩余列表(并入集合)可用。
我的想法是第二种方法会更快一点,但可能不会太多。在所有3个来源都存在之前,我真的不能做太多,所以从第二种方法中获得的并不多,并且引入了争用。
也许还有其他方法可以解决这个问题?此外,由于版本是使用long存储的,并且将有100个(可能是数百万)元素,因此内存分配可能会受到关注(因为这些对象很短暂,所以可能不是很大的问题)
答案 0 :(得分:2)
HashSet是一个选项,因为它有Union和Intersect方法
要使用此功能,您必须覆盖Equals和GetHashCode 良好(唯一)哈希是性能的关键。
如果版本全部为v则为数字,则可以使用数字构建缺少为0的散列。
让Int32玩,所以如果版本是Int10或更低版本可以创建一个完美的哈希。
另一个选项是ConcurrentDictionary(没有并发的HashSet),并且所有三个都加入了它 仍然需要覆盖Equals和GetHashCode 我的直觉是三个HashSets然后Union会更快。
如果所有版本都是数字版本,并且您可以使用0表示缺失,则可以将其打包到UInt32或UInt64中,并将其直接放在HashSet中。联盟然后打开包装。使用bit push<<而不是数学打包解压缩。
这只是两个UInt16但它在2秒内运行 这比Hashing类要快。
如果所有三个版本都很长,那么HashSet <integral type>
将不是一个选项
long1 ^ long2 ^ long3;可能是一个很好的哈希,但这不是我的专业知识
我知道元组上的GetHashCode很糟糕。
class Program
{
static void Main(string[] args)
{
HashSetComposite hsc1 = new HashSetComposite();
HashSetComposite hsc2 = new HashSetComposite();
for (UInt16 i = 0; i < 100; i++)
{
for (UInt16 j = 0; j < 40000; j++)
{
hsc1.Add(i, j);
}
for (UInt16 j = 20000; j < 60000; j++)
{
hsc2.Add(i, j);
}
}
Console.WriteLine(hsc1.Intersect(hsc2).Count().ToString());
Console.WriteLine(hsc1.Union(hsc2).Count().ToString());
}
}
public class HashSetComposite : HashSet<UInt32>
{
public void Add(UInt16 u1, UInt16 u2)
{
UInt32 unsignedKey = (((UInt32)u1) << 16) | u2;
Add(unsignedKey);
}
//left over notes from long
//ulong unsignedKey = (long) key;
//uint lowBits = (uint) (unsignedKey & 0xffffffffUL);
//uint highBits = (uint) (unsignedKey >> 32);
//int i1 = (int) highBits;
//int i2 = (int) lowBits;
}
使用ConcurrentDictionary测试,上面的速度提高了两倍 锁上插件是很昂贵的。
答案 1 :(得分:0)
您的问题似乎适合基于事件的解决方案。基本上为每个来源分配事件以完成数据。使用类型保持全局并发哈希。在您的事件处理程序中查看已完成的数据源,如果您的并发哈希包含当前元素的键,则只需将其添加到列表中,如果不是仅插入具有给定元素的新列表。
但是,根据您的性能要求,这可能会使您的应用程序过于复杂。您的第一种方法是最简单的方法。