3

有经常使用的 Dictionary <Int64, byte>。我的意思是在大数据负载中运行数天的循环中。Int64 来自两个 Int32。该字节恰好是许多非常长的列表中这两个 Int32 之间的距离(计数)。

在这个循环中我需要做的是

  • 生成密钥
  • 如果字典中不存在键,则插入键和值
  • 如果键确实存在并且新值(字节)小于现有值,则将现有值替换为新值

现在我正在使用直接数学来生成密钥,我知道有更快的方法,但我无法弄清楚。我把 shift 作为一个标签,因为我认为这是如何优化它,但我无法弄清楚。

然后当循环完成时,我需要从 Int64 中提取两个 Int32 以将数据插入到数据库中。

谢谢

每个评论我用来将两个 Int32 组合成一个 Int64 的数学

        Int64 BigInt;
        Debug.WriteLine(Int32.MaxValue);
        Int32 IntA = 0;
        Int32 IntB = 1;
        BigInt = ((Int64)IntA * Int32.MaxValue) + IntB;
        Debug.WriteLine(BigInt.ToString());
        IntA = 1;
        IntB = 0;
        BigInt = ((Int64)IntA * Int32.MaxValue) + IntB;
        Debug.WriteLine(BigInt.ToString());
        IntA = 1;
        IntB = 1;
        BigInt = ((Int64)IntA * Int32.MaxValue) + IntB;
        Debug.WriteLine(BigInt.ToString());

最好的密钥可能不是 Int64。我所拥有的是两个 Int32,它们共同构成一个密钥。和一个字节的值。我需要快速查找该复合键。字典很快,但它不支持复合键,所以我创建了一个实际上是复合键的单个键。在 SQL Int32A 中,Int32B 形成 PK。

我不使用复合键的原因是我想要 Dictionary 的查找速度,并且据我所知 Dictionary 不支持复合键。这是生产代码。在 SQL 表中实际上还有第三个键(Int32 sID、Int32 IntA、Int32 IntB)。在这个解析器中,我一次只处理一个 sID(并且 sID 是按顺序处理的)。我从对 SQL 的复合键查找开始(一次运行数十亿次)。当我将 IntA、IntB 拉出到 Dictionary 以处理单个 sID,然后在每个 sID 完成时加载到 SQL,我得到了 100:1 的性能提升。部分性能改进是插入,因为当我从字典中插入时,我可以按 PK 顺序插入。新的 IntA 和 IntB 不是由解析生成的,因此直接插入 SQL 会严重分割索引,我需要在运行结束时重建索引。

4

3 回答 3

11

如果要从 Int32 到 Int64 来回转换,可以使用具有显式布局的结构:

//using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit)]
struct Int64ToInt32
{
    [FieldOffset(0)]
    public Int64 Int64Value;
    [FieldOffset(0)]
    public Int32 LeftInt32;
    [FieldOffset(4)]
    public Int32 RightInt32;
}

只需从字段中设置/获取值。

于 2012-04-01T17:44:46.110 回答
9

听起来你只是想换班。就我个人而言,我发现在使用无符号类型而不是有符号类型时考虑移位更简单:

// Note: if you're in a checked context by default, you'll want to make this
// explicitly unchecked
uint u1 = (uint) int1;
uint u2 = (uint) int2;

ulong unsignedKey = (((ulong) u1) << 32) | u2;
long key = (long) unsignedKey;

并扭转:

ulong unsignedKey = (long) key;
uint lowBits = (uint) (unsignedKey & 0xffffffffUL);
uint highBits = (uint) (unsignedKey >> 32);
int i1 = (int) highBits;
int i2 = (int) lowBits;

您完全有可能不需要将所有这些转换为无符号类型。这对我的理智比其他任何事情都重要:)

请注意,您需要转换u1为 aulong以便在正确的空间中进行移位 - 将 a 移位uint32 位将无济于事。

请注意,这是一种组合两个 32 整数以获得 64 位整数的方法。无论如何,这不是唯一的方法。

(旁注:Bas 的解决方案效果很好——我总是对这种方法有点不舒服,没有具体原因。)

于 2012-04-01T17:44:05.890 回答
1

您可以使用位移将两个 32 位值存储在一个 64 位变量中。

我举一个小例子:

int a = 10;
int b = 5;
long c;

//To pack the two values in one variable
c = (long)a << 32;
c = c + (long)b;
//the 32 most significant bits now contain a, the 32 least significant bits contain b

//To retrieve the two values:
c >> 32 == a
c - ((c>>32)<<32) == b

编辑:我看到我参加聚会有点晚了,如果我没有弄错的话,只是想签入 VS :)

于 2012-04-01T17:55:26.910 回答