2013-10-29 43 views

回答

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決賽。這是行不通的,因爲鍵和值是在運行時通過反射實例化的。這需要一個默認構造函數,因此InputFormat無法猜測填充最終數據字段所需的參數。因此,重用實例的整個概念顯然與不可變性的概念相矛盾。

但是,您應該問自己在Map/Reduce中不可變的鍵/值應該具有哪種好處。在Joshua Bloch的Effective Java第15項中,他指出不可變類更容易設計,實現和使用。他是對的,因爲Hadoop的減速是可變性最壞的例子:

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

在迭代的每個值是指same共享對象。因此,如果許多人將自己的價值觀念變爲正常收藏,並問自己爲什麼總是保持相同的價值觀,那麼他們會感到困惑。最後歸結爲性能的折衷(CPU和內存 - 想象單個密鑰的數十億個價值對象必須駐留在RAM中)與簡單性之間的關係。

+0

謝謝托馬斯。這就解釋了爲什麼可寫數據類型被設計爲可變的。你能否詳細說明你提供的Reduce例子。這是否意味着Reduce將始終只使用集合對象的一個​​實例,並且其值永遠不會被修改? – Raja

+0

@Raja沒有集合對象,'Iterable'是磁盤上的數據的直接代理,它將被序列化並且不斷地只填充一個值對象。 –

2

簡而言之,原因Writable不能是Immutable是方法在WritableHadoop反序列化實例以使用默認(無參數)構造函數創建實例並調用readFields來解析值。由於構造中沒有賦值,因此對象必須是可變的。

+0

謝謝約翰。它闡明瞭爲了參與序列化/反序列化過程,需要將數據類型變爲可變。 Hadoop在反序列化過程中創建(對象)實例的級別。每個任務運行一個對象?如果映射器是多線程的,是否可以創建多個對象來並行地從同一個InputSplit中讀取字段? – Raja

+0

我相信這是每個​​任務運行一個。它創建一個實例,以便在反序列化之前執行Comparable查找。據我所知,Hadoop在單個JVM中沒有多線程映射器。如果這是不正確的,請讓我知道。 –

相關問題