地點:淡水福佑宮旁的老街
機身:Sony A550
鏡頭:Sony 50mm F1.4
快門:1/20s
光圈:F1.4
ISO:200
這張採用定焦大光圈的鏡頭將老街的風貌保存下來~
blog.Ring.idv.tw
In Photography
地點:淡水福佑宮旁的老街
機身:Sony A550
鏡頭:Sony 50mm F1.4
快門:1/20s
光圈:F1.4
ISO:200
這張採用定焦大光圈的鏡頭將老街的風貌保存下來~
2010-09-14 00:41:05 | Comments (2)
In Photography
地點:真理大學內
機身:Sony A550
鏡頭:卡爾蔡斯16-80mm T* F3.5-4.5
快門:1/640s
焦距:80mm
ISO:200
這是昨天所拍攝的眾多照片中最喜愛的其中一張 ^^
2010-09-14 00:09:51 | Add Comment
In Photography
使用黑卡前 - 正常曝光25秒
使用黑卡後 - B快門曝光109秒
地點:八里河岸
機身:Sony A550
鏡頭:Tokina 11-16mm F2.8
焦距:11 mm
光圈:F11
ISO:200
很明顯的~ 透過使用黑卡的拍攝技巧可以取得更多的細節~ ^^
2010-09-13 23:44:04 | Comments (1)
In Hadoop
隨著Hadoop 0.21.0的釋出,你可以更方便的來測試你的MapReduce程式,因為它包含了一套由Cloudera所貢獻用來測試MapReudce程式的Library - MRUnit,不過目前除了官方所提供的overview.html檔之外,其它的相關文件卻相當稀少(補充中:Add MRUnit documentation),而本文純粹記錄一下簡單的WordCount測試程式(New API)來介紹MRUnit的使用方式:
TokenizerMapper
import java.io.IOException; import java.util.StringTokenizer; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; public class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); public void map(Object key, Text value, Context context) throws IOException, InterruptedException { StringTokenizer itr = new StringTokenizer(value.toString()); while (itr.hasMoreTokens()) { word.set(itr.nextToken()); context.write(word, one); } } }
WordCountReducer
import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> { private IntWritable result = new IntWritable(); public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int sum = 0; for (IntWritable val : values) { sum += val.get(); } result.set(sum); context.write(key, result); } }
MRUnitTest
import junit.framework.TestCase; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mrunit.mapreduce.MapReduceDriver; import org.apache.hadoop.mrunit.types.Pair; import org.junit.Before; import org.junit.Test; public class MRUnitTest extends TestCase { private Mapper<Object, Text, Text, IntWritable> mapper; private Reducer<Text, IntWritable, Text, IntWritable> reducer; private MapReduceDriver<Object, Text, Text, IntWritable,Text, IntWritable> driver; @Before public void setUp() { mapper = new TokenizerMapper(); reducer = new WordCountReducer(); driver = new MapReduceDriver<Object, Text, Text, IntWritable,Text, IntWritable>(mapper, reducer); } @Test public void testIdentityMapper() { Pair<Object, Text> p1 = new Pair<Object, Text>(new Object(), new Text("bar")); Pair<Object, Text> p2 = new Pair<Object, Text>(new Object(), new Text("foo")); Pair<Object, Text> p3 = new Pair<Object, Text>(new Object(), new Text("bar")); Pair<Object, Text> p4 = new Pair<Object, Text>(new Object(), new Text("bar")); driver.withInput(p1); driver.withInput(p2); driver.withInput(p3); driver.withInput(p4); driver.withOutput(new Text("bar"), new IntWritable(3)); driver.withOutput(new Text("foo"), new IntWritable(1)); driver.runTest(); } }
由於上述範例主要測試MapReduce整個流程,所以透過「MapReduceDriver」物件來驅動整個測試,當然你也可以只測試Map流程,那就透過「MapDriver」即可,另外MRUnit也支援Counters,所以也可以透過它來驗證程式。
相關資源
2010-09-13 18:01:25 | Add Comment
昨天晚上我和同事在討論一個小程式,該程式只是需要一點小邏輯而已,並不會很複雜~ 而且可以有多種寫法,整個故事如下:
該程式需要進行一些轉換的工作,條件是將「1到12的整數,能轉換成1->12, 2->1, 3->2.... 12->11」這樣的處理,很顯然的~ 這只需要一個「if-else」判斷式即可搞定,程式如下:
if (i == 1) return 12; else return i-1;
看起來相當直覺~ 而且可讀性也還不錯~ 只是龜毛的我硬是想要用公式來解決它,解法如下:
return (i+10)%12+1;
好了,問題來了~ 以程式碼的可讀性來說前者俱備這樣的優勢,唯一可以挑剔的就是和後者相比程式碼多了點...(其實也還好 XD)
那這兩種解法哪一種執行的效率高呢?「if-else」判斷式?還是公式?
筆者寫了個Java程式來測試~ 不過得不到答案,可能是JVM的關係導致一下子解法一快~ 一下子又解法二比較快... Orz
public class Test { public static int test1(int i) { return (i + 10) % 12 + 1; } public static int test2(int i) { return (i == 1) ? 12 : i - 1; } public static void main(String[] args) { long s1 = System.nanoTime(); for (int i = 0; i < 1000000000; i++) test1(i); long e1 = System.nanoTime(); System.out.println(e1 - s1); long s2 = System.nanoTime(); for (int i = 0; i < 1000000000; i++) test2(i); long e2 = System.nanoTime(); System.out.println(e2 - s2); } }
不過可以確定的是,如果只從被編譯後的class檔所包含的opcode來看~ 用公式解的opcode數量少了一個,但是執行測試的結果不代表用公式解的效率就比較好:
public static int test1(int); Code: Stack=2, Locals=1, Args_size=1 0: iload_0 1: bipush 10 3: iadd 4: bipush 12 6: irem 7: iconst_1 8: iadd 9: ireturn public static int test2(int); Code: Stack=2, Locals=1, Args_size=1 0: iload_0 1: iconst_1 2: if_icmpne 10 5: bipush 12 7: goto 13 10: iload_0 11: iconst_1 12: isub 13: ireturn
既然如此,筆者就改用C來測試看看:
#include <stdio.h> #include <time.h> int test1(int i) { return (i+10)%12+1; } int test2(int i) { return (i==1)?12:i-1; } int main(void) { clock_t start_tick, end_tick; double elapsed; start_tick = clock(); for(int i = 0 ; i < 1000000000 ; i++) test1(i); end_tick = clock(); elapsed = (double) (end_tick - start_tick) / CLOCKS_PER_SEC; printf("test1 taken:=%f\n",elapsed); start_tick = clock(); for(int i = 0 ; i < 1000000000 ; i++) test2(i); end_tick = clock(); elapsed = (double) (end_tick - start_tick) / CLOCKS_PER_SEC; printf("test2 taken:=%f\n",elapsed); return 0; }
gcc -std=c99 -o test test.c
測試結果出爐:
test1 taken:=6.090000 test2 taken:=4.050000
「if-else」判斷式獲勝!! Orz... 那我幹嘛還花時間去想公式~ 唯一的好處就只剩下程式比較「美」罷了~ (自我感覺良好...)
最後謝謝我那位同事(匿名)陪我一起討論 ^^
2010-08-24 14:29:30 | Comments (4)