最适合动态语言字段访问的数据结构

时间:2011-01-24 05:40:36

标签: optimization data-structures dynamic hash tree

我正在实现一个动态语言,它将编译为C#,并且它正在实现自己的反射API(.NET太慢了,而且DLR仅限于更近期和资源丰富的实现)。

为此,我实现了一个简单的.GetField(字符串f)和.SetField(字符串f,对象val)接口。直到最近,实现只是切换所有可能的字段字符串值并进行相应的操作。 此外,这种动态语言可以定义匿名对象。对于那些匿名对象,起初我实现了一个简单的哈希算法。

到目前为止,我正在寻找优化语言动态部分的方法,而且我发现匿名对象的哈希算法是过度的。这是因为物体通常很小。我会说对象通常包含2或3个字段。很少,它们将包含超过15个字段。实际散列字符串并执行查找需要花费更多时间,而不是测试它们之间的相等性。 (这不经过测试,只是理论上的。)

我做的第一件事是 - 在编译时 - 为每个匿名对象声明创建一个红黑树,并将它放在一个数组上,以便对象可以以非常优化的方式查找它。

但是,我仍然存在分歧,如果这是最好的方法。我可以去寻找完美的散列函数。更根本的是,我正在考虑放弃对字符串的需求,并且实际上使用2长的结构。

这两个long将被编码为每个支持10个字符(A-za-z0-9_),这主要是对字段大小的良好预测。对于大于此的字段,还将提供接收字符串的特殊函数(较慢)。

结果将是内联字符串(不是引用),并且它们的比较将与长时间比较一样便宜。

无论如何,要找到关于这种优化的好信息有点困难,因为这通常被认为是在vm级别,而不是静态语言编译实现。

有没有人对处理动态调用的最佳数据结构有任何想法或提示?

修改 就目前而言,我真正使用字符串作为长表示和线性二叉树查找。

3 个答案:

答案 0 :(得分:1)

由于您可能会重复使用相同的字段和方法名称,因此string interning之类的内容可以很好地为哈希表生成密钥。它还会使字符串相等性比较为常数时间。

答案 1 :(得分:1)

我不知道这是否有用,但我会把它扔掉以防万一;

如果这是编译到C#,你知道编译时的完整字段列表吗?所以作为一个想法,如果您的代码是

// dynamic
myObject.foo = "some value";
myObject.bar = 32;

然后在解析期间,符号表可以为每个字段名称构建一个int;

// parsing code
symbols[0] == "foo"
symbols[1] == "bar"

然后使用数组或列表生成代码;

// generated c#
runtimeObject[0] = "some value"; // assign myobject.foo
runtimeObject[1] = 32; // assign myobject.bar

并将反射建立为单独的数组;

runtimeObject.FieldNames[0] == "foo"; // Dictionary<int, string>
runtimeObject.FieldIds["foo"] === 0;  // Dictionary<string, int>

正如我所说的那样,希望它会有用。不知道是否会!

答案 2 :(得分:0)

对于如此小的数据集(预期的上限为15),我认为几乎任何散列都比树或甚至列表查找更昂贵,但这实际上取决于您的散列算法。

如果你想使用字典/哈希,那么你需要确保你用于密钥的对象快速返回哈希码(可能是一次构建的单个常量哈希码)。如果你可以防止对象内部的冲突(听起来非常可行)那么你将获得哈希表的速度和可伸缩性(适用于任何真实的对象/类大小)。

想到的是Ruby的符号和消息传递。我相信Ruby的符号只是一个内存引用的常量。所以比较是不变的,它们非常精简,你可以使用像变量这样的符号(我对此有点模糊,并且在这台机器上没有Ruby解释器)。 Ruby的方法“调用”真的变成了消息传递。类似于:obj.func(arg)变为obj.send(:func, arg)(“:func”是符号)。我想象这个符号会使对象内部的消息处理程序(我称之为)非常有效,因为它的哈希代码很可能不需要像大多数对象那样计算。

也许在.NET中可以做类似的事情。