薄荷因為嫌他的 blog 速度太慢,轉而尋求其他 database back-end 的方案,比較了 MySQL、PostgreSQL、Berkeley DB 以及 SQLite 等四種解決方案。他的測試結果是:
MySQL: 3 min 17 sec
PostgreSQL: 3 min 50 sec
Berkeley DB: 4 min 32 sec
SQLite: 4 min 36 sec
我也曾經訝異於,宣稱比 MySQL 快上一籌的 SQLite,竟然會輸給 MySQL。後來搜尋文件與實驗後,才曉得,如果把 SQLite 的 sychronization (transaction) 功能關掉的話,SQLite 就可以在速度上領先 MySQL。
原理很簡單,Berkeley DB 和 SQLite 這種 file-based 資料庫,為了要因應 multi process 的環境,只好使用 file lock 來處理 concurrent access 的需求。也因此必須每次都 [...]
今天搞了一個下午,結論就是這個教訓:小心繼承 iostream 的邊際效應 (side effect)。白話一點,就是不要在與 I/O 不相干的地方偷懶對 C++ iostream 使用繼承。
去年年中寫了一個簡單的小 database wrapper 程式庫,一樣是因為不方便使用四處可見的既有 library,所以得自己搞。裡面有一個 class 叫做 Statement,我希望它的用法就跟 cout 一樣,因為數字在 SQL 指令裡,一樣是以字串的形式呈現,另外,這樣也有機會可以依據傳入的型別的不同,自動決定要不要加 SQL 引號,以及要不要 escape 掉插入內容的引號。既然用法就像 cout 一樣,那就乾脆繼承自 ::std::ostream,然後一堆程式都不必寫了。
結果今天在用 Statement 的時候,要把一個 time_t 的值插入 SQL 裡,因為應該也必須,我有在程式一開始的時候設定好 locale 為正體中文,結果要插入的 1423912421 就變成了 "1,423,912,421",多了三個逗號,產生了錯誤的 SQL 指令。很明顯地,因為偷懶繼承 ::std::ostream 的關係,現在必須承受所帶來的 side effect 的苦果。
更糟糕的是,C++ 的 locale/iostream,大概是除了 STL 之外,另外一個 compiler vendor 很容易沒有做到 standard [...]
從 Richy's Blog 的網摘看到這篇《TREE MAN》,真不曉得 Richy 是怎樣一天看這麼多 blog 才有辦法挑出這些來的。
寫程式的時候,也會有這個狀況耶。尤其是當沒有特意使用軟體工程、進度、範疇規劃的時候,特別容易這樣。好像創作就是這麼一回事。當一開始創作,創作品就好像有了生命一般,會自己生長。而創作者的良囿,就在於能否引導創作品,循著有道理或有美感的方向生長,而不是胡亂長個一通,最後變成亂糟糟地什麼也不是。
可惡,今天下午花了那麼久的時間,嘗試了無數的原因,就是找不到為什麼無法順利轉出正確的 UTF-8 資料來的原因。結果回家洗澡時才想到,出來確認一下,果然,我忘記 set locale 了。 我的青春啊,哭~ 所以,寫 main() 的時候,第一步千萬記得要 setlocale() 啊,真是血淚的教訓。
在 Standard C 裡頭,僅規定了我們可以利用 setlocale() 函式,來查詢或設定 C run-time 所用的,全域且唯一的 locale。然而,standard C 並沒有規定,傳進 setlocale() 的第二個參數,locale id,的格式與規定,而是交由各平台 (OS) 自訂。
所以問題來了,假若我們需要在程式裡 hard code 這個 locale id,以便傳給 setlocale(),那就會產生 portability 的問題。
解決辦法可以是,我們預先準備一張表格,訂定一套虛擬的 locale id 表格,在 compile-time 或 run-time 轉換成目標平台所用的 locale id。在 compile-time 我們可以利用 pre-processor 的 #define 來編寫這個表格,在 run-time 則建立 structure,linear-search 查表即可[1]。這樣子,我們就可以把 portability 問題,侷限在這個表格裡,且一併可達到 code-reuse 的目標。
因此,問題就轉換成了,我們怎樣建立與維護這個表格?這個表格不必太完整,但至少會用到的平台與 locale,都應該在裡面有資料。
今天就是碰到這個麻煩的問題。原本我僅為這個表,建立了正體中文,Windows、Linux/FreeBSD 的資料,因為大約也只會用到這麼多。更因為平常根本就是在正體中文裡頭跑,setlocale() 時直接就傳長度為零的字串 [...]
有時候,為了效率,不得不用比較糟糕的程式寫法,好比說,全域變數 (global variable) 的使用。不過,真的是這樣子嗎?多使用全域變數,真的可以讓程式的執行效率變高嗎?
一般來說,CPU 會有多種定址模式 (addressing mode),可以給 array、pointer 用,難道這些定址模式,沒有增進 array、pointer 使用效率的功能嗎?當效率至上的時候,如果使用全域變數,可以增進效能很多的時候,當然我們可以考慮犧牲維護性 (mantainability)、可讀性 (readability);但如果效能只有增進一點點,那全域變數的使用,就會變成值得商榷思考,慎重考慮的選項了。
所以,我們最好做個實驗,看看到底效能的差異有多少。測試程式如下:
#include <stdio.h>#include <stdlib.h>
#define INDIRECT_ACCESS 1
#define VAR_NUM (1024 * 32)#define LOOP_NUM1 (1024)#define LOOP_NUM2 (1024)
int global_var[VAR_NUM];
struct struct_var_t{ int v[VAR_NUM];};
struct struct_var_t* struct_var;
#if INDIRECT_ACCESS# define ACCESS_VAR struct_var->v#else# define ACCESS_VAR global_var#endif
int main(){ int i; int [...]
最近在讀《Imperfect C++ / Practical Solutions for Real-Life Programming》這本書,是 Matthew Wilson 寫的,有常在讀 C/C++ Users Journal 的人,應該對他不陌生。不過,開始上班後,自己可以用來讀書的大塊時間變少了,所以到現在才剛把第一章唸完。
第一章主要是在講 Design by Contract,在 C++ 裡,其所需之相關技術,最重要的大概就屬 static assertion 與 type traits 了。要實作這兩種技術,最好的 reference design 當屬 boost 裡的 static_assert 與 type_traits 這兩個 libraries。
由於不方便直接採用 boost,故必須自己實作一個來用,而我一直到了最近幾天,才真的開始動手。遲到最近的主要原因是因為,type traits 真的很難寫,必須對各個 compiler 的特性與行為,有深入地瞭解才行。有興趣的人,可以去稍微 trace 一下 boost 是怎麼實作 type_traits,便可知其難度。
這本書的第一章裡,最讓我覺得值得一提的是,最後面的最後一段話:
It's worth noting that both the invalid index [...]
剛同事跑來問我 wstring 的問題,一看,哈!碰過了。問題是這樣子的,在 GCC 2.9x 上想要使用 wstring 卻無法使用,compile 時會出 error。原因有二:
第一個原因是,至少在 FreeBSD 4 以及我同事用的某一版 Linux 上,GCC 2.9x 沒有為我們預先 typedef std::basic_string<wchar_t> 為 std::wstring,因此無 wstring 可用。不過,我們可以自行 typedef 如下以解決這個問題:
#if (defined(__FreeBSD__) && defined(__GNUC__) && (__GNUC__ == 2))
# include <string>
namespace std {
typedef std::basic_string<wchar_t> wstring;
[...]
前陣子我在 blog 上簡單介紹了 Trac Aggregator,因為在工作上總是必須多個專案同時進行,相互依存,又因為當初規劃 repository 的決策,造成搭配 Trac 時,因為 Trac 沒有 multi-project support,而使用起來非常麻煩[1]。所以只好簡單地寫了這個 PHP script 當作個人工作用的 issue portal。
其實說穿了很簡單,Trac 的 report 是藉由讓使用者自行編輯 SQL 指令而產生的。而 Trac 的資料庫就放在 TRAC_ENV 下的 db/trac.db 這個 SQLite 資料檔裡。所以我們只要自己用 PHP 開 SQLite 資料檔,然後把 Trac 裡的 report 的 SQL 指令搬過來,排版 output 一下,簡易版 Trac Aggregator 就完成了。
比較麻煩的,反而是如何呈現跨專案的 ticket list。由於每個專案的 milestone 進度都不會相同,排序的問題就相對地複雜很多。目前我只是簡單地在 script 裡,用 compositional compare function [...]
來追一下 Ajax 技術吧。:-) 研究分析:
Flickr: From Flash to Ajax
參考資料:
Ajax: A New Approach to Web Applications - 介紹 Ajax 的文章。
BackBase-Axaj-based RIA - 自從 Flickr 棄 Flash 而就 Ajax 之後,Ajax 這個詞就紅了起來。其實概念很簡單,不過大環境到最近才成熟。三、四年前的時候,大家就有在幻想這樣的架構,但根本作不出來。因為 browser 彼此之間的相容性太差,與 W3C 標準差別太大,根本很難下手。再加上那時候的 W3C 的標準,也過於陽春,Ajax 需要的一些關鍵技術,也尚未成熟。現在技術成熟了,也許漸漸地市場上就可以看到 Ajax 相關的程式庫甚至 framework 出現了,好比阿修現在推薦的 BackBase 這間公司的產品。
Ajax and FlickrJS - 既然 Flickr 開始用 Ajax 了,當然原本的 Flickr API 就也該有個 [...]