我的雲端生活網 - Life+

Thursday, December 3, 2009

程式風格與系統實作

有個著名的99題程式問題集中有二件基本問題:
  1. 反轉一列資料。
  2. 檢查一列資料是不是回文。
用 Erlang 寫,程式如下:

reverse( [ ] ) -> [ ] ;
reverse( [ X | Y ] ) -> reverse( Y ) ++ [ X ] .

palindrome( Xs ) -> reverse( Xs ) == Xs.

這些問題主要是在考邏輯程式語言或函數程式語言解決問題的方法,用 Erlang 寫非常自然。至於考慮到用指令式程式語言,程式會怎麼寫呢?先想想 C 程式。
void reverse(char *x, int xn, char *y, int yn) {
    int i;
    yn = xn;
    for(i=0; i<xn/2+1; i++) {
        y[i] = x[xn-1-i];
        y[yn-1-i] = x[i];
    }
}

main() {
    char a[] = {'a', 'b', 'c', 'd', 'e'};
    char b[] = {'1', '1', '1', '1', '1'};
    reverse(a, 5, b, 5);
}
以上程式是反轉一列資料。至於檢查是不是回文,與反轉一列資料有相當的程式結構。所以,照著反轉程式結構可以改出檢查回文的程式。

/* void reverse */ int is_palindrome(char *x, int xn /* , char *y, int yn */ ) {
    int i;
    // yn = xn;
    int result = TRUE;
    for(i=0; i<xn/2+1; i++) {
        // y[i] = x[xn-1-i];
        result &= (x[i] == x[xn-1-i]);
        // y[yn-1-i] = x[i];
    }
    return result;
}

Erlang 程式和 C 程式各自從掌握的不同邏輯意思解決問題。對 Erlang 程式來說,一列資料是回文隱含了將這一列資料反轉會和原資料相同。對 C 程式來說,是考慮到一列資料若是回文,資料每一項在前半段位置的,會和在後半段鏡射位置的資料相同。所以,用 C 寫以上程式,一定要把以上二個程式寫成一樣的結構,因為它們的順序邏輯一樣。但是用 Erlang 寫程式,則可以說是反轉資料問題是檢查回文問題的子問題。不同的語言有各自解決問題的能力。用 C 的程式風格思考, Erlang 真不好寫;並且用 Erlang 的程式風格思考, C 也不好寫。不過,只要用 Erlang 的方式寫 Erlang 程式,用 C 的方式寫 C 程式,都是做對事情了。

所以,本篇文題回到系統實作方面:本來我有個系統是用 Perl 規則持續讀檔案,用檔案時間判斷是否有新的 RFID reader 讀數出現。系統中存在大量這種類型的 Perl 規則,並且反覆判讀檔案消耗大量時間。我可以用 MapReduce 來節省工作時間嗎? MapReduce 本身就是前車之鑑。

在有大量資料需要處理的分散系統上,要直接寫程式,不管是什麼檔案鎖定、程序鎖定、或是信號的控制機制,最後都是普通的程式處理方式:把大量資料塞進一個迴圈裏。 MapReduce 是個漂亮的程式作法,它的思考方向是程式有多少等級的數量,程式也產生出多少等級數量的程序,讓每個程序分配到相當少量的工作,許多程序一起做!所以,前後二種處理方法,在程式的寫法上相當不同。直接的程式,想法依然直接。但是,實作 MapReduce 是先做一個計算框架,框架中有二種空位存放 map 和 reduce 二種類型的程式;而中樞設計不要思考 map 和 reduce 程式可能怎麼寫,而是只思考把一些程序分配去執行 map 程式、另一些程序分配去執行 reduce 程式,並且這些程序如果中斷但沒做完工作,就再分配一次同樣的工作。於是,剩下的工作是 map 和 reduce 程式都比較好寫,而且寫完並套進 MapReduce 架構之後,就可以處理大量的資料。同樣的問題處理,可以用不同的程式方法解決問題。

依我看,現有系統的規則,只有檢查新 reader 讀數的規則可以保留,直接寫成 map 程式。

rfid_read ( File, Reads ) :
    for each (Tag_ID, Reader_ID, Time) in Recent(Reads)
        emit( (observation, (Tag_ID, Reader_ID, Time)) )

然後交給其他的 reduce 程式處理。至於其他類型的規則,則要按照 MapReduce 的思維改寫成適當的 map 程式或 reduce 程式比較好。

No comments:

Blog Archive