【问题标题】:Why should a Writable datatype be Mutable?为什么可写数据类型应该是可变的?
【发布时间】:2013-11-08 07:17:55
【问题描述】:

为什么可写数据类型应该是可变的? 在 Map、Combine、Shuffle 或 Reduce 过程中使用 Text(相对于 String)作为 Key/Value 的数据类型有哪些优势?

感谢和问候, 拉贾

【问题讨论】:

    标签: java hadoop mapreduce writable


    【解决方案1】:

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

    【讨论】:

    • 谢谢约翰。它阐明了数据类型需要是可变的才能参与序列化/反序列化过程。在去序列化过程中,Hadoop 将在什么级别创建(对象)实例。每个任务运行一个对象?如果 Mapper 是多线程的,是否可以创建多个对象从同一个 InputSplit 中并行读取字段?
    • 我相信每个任务运行一个。它创建一个实例以便在反序列化之前进行 Comparable 查找。据我所知,Hadoop 不在单个 JVM 中使用多线程映射器。如果这不正确,请告诉我。
    【解决方案2】:

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

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

    // 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) ...
    

    iterable 中的每个值都引用same 共享对象。因此,如果将他们的值缓冲到一个普通的集合中,很多人会感到困惑,并问自己为什么它总是保留相同的值。

    归根结底,它归结为性能(cpu 和内存 - 想象一下单个键的数十亿个值对象必须驻留在 RAM 中)与简单性之间的权衡。

    【讨论】:

    • 谢谢托马斯。这让我明白了为什么 Writable 数据类型被设计为可变的。您能否详细说明您提供的 Reduce 示例。这是否意味着 Reduce 将始终只使用集合对象的一个​​实例,并且它的值永远不会被修改?
    • @Raja 没有集合对象,Iterable 是磁盘上数据的直接代理,它将被序列化并不断地重新填充一个值对象。
    猜你喜欢
    • 2011-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-07
    相关资源
    最近更新 更多