为什么可写数据类型应该是可变的? 在 Map、Combine、Shuffle 或 Reduce 过程中使用文本(与字符串相比)作为键/值的数据类型有哪些优势?
感谢和问候, 拉惹
最佳答案
你不能选择,这些数据类型必须是可变的。
原因是序列化机制。让我们看一下代码:
// version 1.x MapRunner#run()
K1 key = input.createKey();
V1 value = input.createValue();
while (input.next(key, value)) {
// map pair to output
mapper.map(key, value, output, reporter);
...
所以我们再次重用相同的键/值对实例。 为什么? 我不知道当时的设计决策,但我认为这是为了减少垃圾对象的数量。请注意,Hadoop 非常古老,那时垃圾收集器的效率不如今天,但即使在今天,如果您映射数十亿个对象并将它们直接作为垃圾丢弃,也会在运行时产生很大差异。
不能使Writable
类型真正不可变的真正原因是您不能将字段声明为final
。让我们用 IntWritable
做一个简单的例子:
public class IntWritable implements WritableComparable {
private int value;
public IntWritable() {}
public IntWritable(int value) { set(value); }
...
如果你想让它不可变,它肯定不再适用于序列化过程,因为你需要定义 value
final。这是行不通的,因为键和值是在运行时通过反射实例化的。这需要一个默认构造函数,因此 InputFormat
无法猜测填充最终数据字段所需的参数。因此,重用实例的整个概念显然与不变性的概念相矛盾。
但是,您应该问问自己,不可变的键/值在 Map/Reduce 中应该有什么样的好处。在 Joshua Bloch 的 Effective Java 的第 15 项中,他指出不可变类更易于设计、实现和使用。他是对的,因为 Hadoop 的 reducer 是可变性最糟糕的例子:
void reduce(IntWritable key, Iterable<Text> values, Context context) ...
可迭代对象中的每个值都引用相同
共享对象。因此,如果许多人将他们的值缓冲到一个正常的集合中并问自己为什么它总是保留相同的值,许多人会感到困惑。
最后,它归结为性能(CPU 和内存 - 想象一下,单个键的数十亿值对象必须驻留在 RAM 中)与简单性之间的权衡。
关于java - 为什么可写数据类型应该是可变的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19653072/