为什么Writable数据类型应该是可变的?

时间:2013-10-29 08:25:57

标签: java hadoop mapreduce writable

为什么Writable数据类型应该是可变的? 使用Text(vs String)作为Map,Combine,Shuffle或Reduce进程中Key / Value的数据类型有什么好处?

谢谢&问候, 拉加

2 个答案:

答案 0 :(得分:4)

您无法选择,这些数据类型必须是可变的。

原因是序列化机制。我们来看看代码:

// 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的减速器是可变性最糟糕的例子:

void reduce(IntWritable key, Iterable<Text> values, Context context) ...

iterable中的每个值都指向same共享对象。因此,如果他们将他们的价值缓冲到正常的集合中并且问自己为什么它总是保留相同的值,那么很多人会感到困惑。

最后,它归结为性能的折衷(cpu和内存 - 想象一个密钥的数十亿个值对象必须驻留在RAM中)与简单性相比。

答案 1 :(得分:2)

简单地说,Writable的原因Immutable readFields(DataInput) Writable方法HadoopreadFields反序列化实例以使用默认(无参数)构造函数创建实例并调用{{1}}来解析值的方式。由于未在构造中分配值,因此对象必须是可变的。