今天我要回家吃午餐,母親大約一週前就先跟我預約了,說要全家一起去吃美侖大飯店。事實上,不久前我們也有預計要去,不過當天去電詢問發現已經客滿,所以這次母親特地早早就預約。我本來還在想為什麼母親對於美侖大飯店如此執著,後來知道原來最近飯店有舉辦活動,花蓮鄉親四人同行一人免費,我們家剛好就四人 XD
回到家時發現隔壁家搭起了帳棚,要辦喪事。母親聊天時說最近附近陸陸續續死了好多人…… 奶奶在這裡最要好的朋友也死了,而且已經死了快半年,我卻現在才知道,真是滿讓我驚訝的。
美侖的午餐是自助式的 Buffet ,跟上次來吃的下午茶差不多,不過這次我對正餐類比較沒興趣,倒是吃了一大堆甜點。有一道芒果奶酪非常讚,奶酪相當堅挺,不太會碎掉,很有口感;另外還有一道大理石重乳酪蛋糕也是極品,乳酪濃而不膩,但我因為吃芒果奶酪吃到很飽,消化了一陣子才再次出擊,而這時乳酪蛋糕已經只剩一塊了…… 我總共只吃到兩塊 orz
用完餐後,我們到市區逛衣服。 HANG TEN 的某個店員說話真是老實不客氣,我拿著某件衣服走向試衣間,她馬上快步過來提醒我要看尺寸,我還真的是忘了看 XD 我把衣服交給她,她就說:「這是 S 的,你這麼壯,應該要穿 XL 的。」然後她便去幫我找 XL 的尺寸,但這件剛好沒有 XL ,接下來她就一直跟我隨便亂推薦,到這裡為止我還只是覺得有點煩人而已。她繼續跟著我們推銷,然後突然發現原來旁邊這位是我弟,於是她就發言了:「原來這是你弟弟喔!怎麼你弟這麼瘦,你這麼壯。」我聽了啞口無言…… 接下來一路上弟弟就一直虧我胖 orz
回家後我管理了一下我的城邦,然後很反常地去睡了午覺。我已經兩天沒有好好睡一覺了,不是很難入眠,就是好不容易入眠後,才兩小時又醒了…… 一直斷斷續續的都沒睡好。但也因此最近的生產力滿不錯的,我寫了一個全新的 Plugin 、更新了至少四個 Plugin ,然後還給我所有 Plugin 各寫了份簡單的文件,現在又在計畫下一個 Plugin 了 XD 不過我的下一個計畫有點難寫,思考了好久不知從何下手,又不是常用的功能,所以應該會先擱置 :p
其實這篇文章跟上一篇是有點關聯的…… 我為了解決 Memory Leak ,抱著「反正我本來就還有另一個問題要靠 BackgroundWorker 來解決,不如碰碰運氣」的心態,將耗時又耗記憶體的那段程式改寫為 BackgroundWorker ,結果真的有用耶~ 所以我沒有嘗試 GC.Collect() ,因為用這種有副作用的 function 會覺得不太漂亮 :p
BackgroundWorker 的效果跟 Thread 差不多,但更容易使用,方法如下:
- 把 BackgroundWorker 元件拉進來,取名為
BGWorker1 。
- 將 WorkerReportsProgress 設為 True ,讓 BackgroundWorker 回報進度。
雙擊 DoWork 事件,然後如下撰寫:
private void BGWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// 另外根據 sender 建立一個 BackgroundWorker
BackgroundWorker bw = sender as BackgroundWorker;
// 取出參數,我不知道怎麼改成能夠取多參數的版本… 此例中 YourFunction 的第二個參數是 int
int arg = (int)e.Argument;
// 開始執行你要的工作
e.Result = YourFunction(bw, arg);
// 處理使用者按下「取消」的動作
if (bw.CancellationPending)
{
e.Cancel = true;
}
}
雙擊 RunWorkerCompleted 事件,然後如下撰寫:
private void BGWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
// 使用者中止了執行
}
else if (e.Error != null)
{
// 執行中發生錯誤,可用 e.Error.Message 得到錯誤訊息
}
else
{
// 執行作業正常完成
}
}
雙擊 ProgressChanged 事件,然後如下撰寫:
private void BGWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// 用 e.ProgressPercentage 可以取得目前執行進度百分比(0-100)
}
比較實用的範例:
private long begin_tick = 0L;
private void BGWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// 取得工作開始的時間,記得要在 RunWorkerCompleted 中將 begin_tick 設回 0L
// C# 中有 function scope 的 static variable 嗎?
if (begin_tick.Equals(0L))
{
begin_tick = DateTime.Now.Ticks;
}
// 計算已執行時間
TimeSpan elapse_time = new TimeSpan(DateTime.Now.Ticks - begin_tick);
// 預估完整執行所需時間
long total_tick = elapse_time.Ticks * 100L;
// 避免 Division by Zero…… 這有更方便的寫法嗎?
if (!e.ProgressPercentage.Equals(0))
{
total_tick /= e.ProgressPercentage;
}
// 預估剩餘時間
TimeSpan remain_time = new TimeSpan(total_tick - elapse_time.Ticks);
// 預估完成時間
DateTime finish_time = new DateTime(DateTime.Now.Ticks + remain_time.Ticks, DateTimeKind.Local);
ProgressBar.Value = e.ProgressPercentage;
StatusLabel.Text = String.Format("{0}% (經過時間:{1:00}:{2:00}:{3:00} / 預估剩餘:{4:00}:{5:00}:{6:00} / 預估完成:{7})", e.ProgressPercentage, elapse_time.Hours, elapse_time.Minutes, elapse_time.Seconds, remain_time.Hours, remain_time.Minutes, remain_time.Seconds, finish_time.ToString("yyyy-MM-dd HH:mm:ss"));
}
至於 YourFunction 則類似這樣:
private void YourFunction(BackgroundWorker bw, int progress)
{
if (!BGWorker1.CancellationPending)
{
// 執行你要執行的作業
// 回報目前執行進度百分比(0-100),沒錯,你必須自己計算
BGWorker1.ReportProgress(progress);
}
}
傳入參數是陣列,使用 for 迴圈的範例:
private void YourFunction(BackgroundWorker bw, string[] argument)
{
int count = argument.Length;
for (int i = 0; i < count; i++) {
if (!BGWorker1.CancellationPending)
{
using (SomeClass obj = new SomeClass(argument[i])) {
BGWorker1.ReportProgress(i * 100 / count);
}
}
}
}
今天的 meeting 改到下午,所以我無聊了一個上午,當同學們陸陸續續出現時,我便興奮地跟大家分享我的進度 >ω< 堅哥也很驚訝我的進度怎麼突然變得這麼快…… 不過這都不是今天的重點!今天的重點是~ 堅哥說有一個計畫下來了,所以現在有很多經費,他提議要買液晶電視、家庭劇院這些設備,在這段討論途中我就不斷地穿插:「可是空有這麼好的設備,沒有東西來配合也沒用嘛~」,最後堅哥終於被我的怨念感動到,允許我們買 Wii 了!(我們也考慮過 PlayStation 3 和 XBOX360 ,最後由於 Wii 最便宜而勝出)
熊跟我說這樣我們就可以再把 Lab 網站改回 Wii 的版面,不過我想堅哥不會同意這種事的 XD
明天是已經延了一週的 meeting ,而我今天卻還沒有進度可以報告,所以我決定今天到 Lab 努力一天。最近進度會如此緩慢,「沒有方向」是其中一個原因,不過兩天前當我去跟熊催討決策樹程式時,我發現熊已經難以壓抑、幾乎要爆炸了,所以我就想:「嗯… 我還是自力更生吧!」。
今晚我本來的目標只是要實作完我的計分方法,並且找出計分方法中的問題,不過修改演算法好難,我改了一陣子就感到腸枯思竭,於是決定先研究決策樹。我去把 Weka 抓下來,然後照著 IKVM with Weka tutorial 這篇教學作,意外地非常簡單,而且因為 IKVM 用 Reflection 實作了 IntelliSense ,所以在 Visual C# 裡寫起 Java 就跟寫 C# 一樣自然, IntelliSense 不只是能減少打字的麻煩,某種程度上,它可以讓寫程式就像是一連串的選擇題 XD
不過最後我還是沒有在 C# 裡面寫 Java ,因為我打開 Weka 之後發現…… 我完全可以在 Weka 裡面完成我的實驗,不需要再寫一個新的、專門化但是功能較少的 GUI 。發現了這點之後,我便又回到計分方法的實作,並且將我現有的程式與計分模組整合,然後產生出資料丟給 Weka 。 Weka 竟然可以直接幫我作 K-fold cross-validation ,連 Recall、Precision、F-measure 也一併算給我,實在是超方便!結果今天的進度很意外地就超前了好多,幾乎算是已經把實驗作完,只剩下寫論文了 XD