發表文章

目前顯示的是 八月, 2011的文章

Synchronization and the Java Memory Model 筆記

昨天看 Effective Java 提到 synchronization 同時提供 exclusive execution 和 communication, 但多數人會忽略後面這點。原本不懂這是什麼意思, 看了《Synchronization and the Java Memory Model》才知道是怎麼回事, Java Memory Model 真的和直觀的想法很不一樣。記錄一下筆記。 final class SetCheck { private int a = 0; private long b = 0; void set() { a = 1; b = -1; } boolean check() { return ((b == 0) || (b == -1 && a == 1)); } } 這段程式有可能 return false, 因為 set() 裡的 a、b 設值可能會順序相反, set 和 check 可能同時被交錯執行。Java 只有保證單一 thread 自己執行的時候, 看起來像按順序由上而下、由左而右執行 (文中用 as-if-serial 表示, 這詞還滿妙的)。 在 multi-thread 時, 情況不同, 各個 thread 有自己的 memory, Java 沒有保證什麼時候 thread 之間才會看到更新後的情況, 這點滿可怕的。但可以用 synchronization lock 或宣告 volatile 強迫 thread 之間同步資料。我想這就是書上說 communication 的意思。 Java 有保證除 long 和 double 外的欄位, 更新值的時候是 atomic 的 (也就是包含 reference), 而 volatile 宣告的欄位也都是 atomic, 包含 volatile long 和 double。這裡要注意幾點: i++ 包含 i + 1 和設值兩個操作, 沒有 atomic。所以設 volatile 也會有危險, 有需要的話還是要用 synchronized, 或照 Effective Java 的建議, 看能不能用 java.util.concurrent.atomic 的類別滿足需求。 lo…

Effective Java 讀書筆記: Item 66 - 用 synchronized 確保 concurrency

這節提供一個不直覺的錯誤package trial; import java.util.concurrent.TimeUnit; public class Trial { private static boolean stopRequested; public static void main(String[] args) throws InterruptedException { Thread backgroundThread = new Thread(new Runnable() { public void run() { int i = 0; while (!stopRequested) { i++; System.out.println(i); } } }); backgroundThread.start(); TimeUnit.SECONDS.sleep(1); stopRequested = true; } } 作者說在沒用 synchronization 機制的情況下, Java 沒有保證 thread 什麼時候看到彼此之間的修改。上面的例子, 在作者的機器上不會停。不過我自己試的結果是一秒後結束。作者說原因是 JVM 有可能最佳化 while 那行, 變成只檢查一次 stopRequested, 結果就不會停了。這個 VM 最佳化技巧叫做 hoisting (文中的例子則是改用 stack 上的變數取代 heap 上的)。 解法是宣告 stopRequested 時加上 volatile。不過作者後來接著強調 volatile 很難寫對, 叔叔有練過, 小朋友別亂用 volatile, 乖乖用 java.util.concurrent.atomic 下的類別, 像是 AtomicLong。這個 package 下的東西用了 machine-level 的方法減少 lock overhead, 比用 synchro…

shell script 處理含空白字元的檔名

以前我習慣寫 for f in $(ls mydir) do ... done 但遇到檔名有含空白時就炸了, 像這樣 $ ls mydir/ | cat a b c $ for f in $(ls mydir); do echo $f; done a b c 解法是設 IFS 這個變數 $ IFS=$'\n' $ for f in $(ls mydir); do echo $f; done a b c unset IFS 也可用這個方式在 shell script 裡做到等同於「字串陣列」files=$(cat <<EOF 1st line 2nd line 3rd line EOF ) IFS=$'\n' for f in $files do echo $f done unset IFS 最後附上 man bash 裡的說明:
The Internal Field Separator that is used for word splitting after expansion and to split lines into words with the read builtin command. The default value is ``<space><tab><new‐ line>''.

virtualbox 使用 USB 裝置

2012-12-16 更新 現在 (4.x 版) 似乎無需做任何設定, 只要有裝 Oracle VM VirtualBox Extension Pack, 在 VirtualBox 視窗右下角按 USB 的圖示, 再點目標裝置, 即可加入或移除該裝置 同一時間只有 host 或 guest 可擁有該裝置, 所以從 guest OS 移除, 相當於接回 host OS 目前 VirtualBox 只支援 USB 2.0 的插槽, 若偵測不到時, 注意一下是否為這個問題 有時拔拔插插, VirtualBox 會進入奇怪的狀態, 接上去 guest OS 無法連接且跳出 device is busy 的錯誤訊息。試看看拔除該裝置, 重開 guest OS (續上則) 若重開 guest OS 無效, 並且 host OS 已移除該裝置, VirtualBox 的 USB 清單卻仍顯示 "captured", 試看看拔除該裝置, 重開 host OS原文網路上搜一下, 比較多是 Ubuntu 當 host 的解法, 我的情況是 Win7 當 host, Ubuntu 當 guest。 這兩篇說明很詳細《Learn How to Set Up USB and Networking Options in VirtualBox》《幻影千瞳的部落格: VirtualBox 使用筆記(二):使用 USB 裝置》 現在的版本圖形介面很好用了, 不用像第二篇說的那樣用指令操作。這裡記下我的操作步驟: 關掉 guest OS 在 VirtualBox 選單, 選擇 guest OS -> Settings -> USB -> Enable USB 2.0 會出現訊息框, 說明要安裝 Oracle VM VirtualBox Extension Pack。下載後安裝它 host OS 插入 USB 隨身碟 在 VirtualBox 選單, 選擇 guest OS -> Settings -> USB, 點右邊有綠色 "+" 的 USB 頭的圖示, 選擇該 USB 隨身碟, 加入它的 filter 從 host OS 移除 USB 隨身碟 開啟 guest OS 插入 USB 隨身碟, 於是 guest OS 會自動偵測…

用 Sphinx 寫文件

以下是最近試用 Sphinx 的心得, 有錯還請指正。 我原本很納悶, 專案文件是用 Wiki 寫好, 還是用 Sphinx 寫來得好。為啥要特別做個工具來產生文件呢? 抱著實驗的性質試了 Sphinx, 試下去才明白, 難怪不少專案用 Sphinx 來寫。 用 Sphinx 寫有幾個好處: 文件原始碼可和程式碼放在同一個 repository, 也可藉此順便做版本管理。不過我覺得以版本管理來說, 還是沒 Wiki 方便。 可透過語法載入程式碼內的註解, 這點 Wiki 就沒輒了, 我覺得這是用 Sphinx 的最大優勢。 一堆好用的 plugin, 像是畫圖、寫數學式子、畫 graph等。將 graphviz 原始碼直接寫在文件裡, 還挺方便的, 不過這點 Wiki 也辦得到。 可嵌入 ipython 語法, 顯示 ipython 的結果, 包含自動填入執行結果等功能。這個相當好用, 適合寫執行的範例 (寫實例演練的必備工具), Wiki 就沒有啦。 產生的結果是純 html, 並有提供文章搜尋功能 (實作方式很妙, 建好 index 存成 js 程式碼, 透過 js 執行搜尋)。架網站提供文件時, 不需另裝任合套件 (PHP / CGI / Web framework / etc)。 功能彈性, 若是 Python guy 的話, 缺什麼語法可自己寫 extension 補一下。Sphinx 也有提供巨集功能自定語法。相較之下, Wiki 最大的好處是編完存檔就看到結果, 省掉 make html 的步驟, 方便大家隨時一起共筆, 提供 lock 避免多人同時編輯相衝, 方便查閱版次之間的差異。Sphinx 得透過 VCS 做, 也不方便提供 html 的版次差異。所以若是多人同時共筆, 偏重於功能說明, Wiki 還是較方便。 這裡列幾個熱門專案選擇的做法: 用 Sphinx: pythonpipvirtualenvDjangoSouth Wiki: 除 MercurialLuceneHadoopMoinMoinWikis (python 寫的 wiki), 另有不少專案的文件量不多, 會直接用 Google Codegithub 提供的 Wiki 寫文件。看完後發覺 ........, 一時好像也看不出個什麼頭緒, 之後再慢慢觀察吧…

Sphinx 的 autodoc 載入問題

為了使用 autodoc, 我在 conf.py 裡這樣寫:sys.path.append('/usr/lib/python2.5/site-packages/Sphinx-1.0.7-py2.5.egg/sphinx/ext') extensions = ['graphviz', 'autodoc'] 結果跑出:autodoc documenter <class 'autodoc.ModuleDocumenter'> must be a subclass of Documenter 正確的寫法是:extensions = ['sphinx.ext.graphviz', 'sphinx.ext.autodoc'] 開 pdb 追下去, 發現是 sphinx.application 和 sphinx.ext.autodoc 之間 circular import 造成的問題。 在 sphinx.application 裡:def add_autodocumenter(self, cls): from sphinx.ext import autodoc autodoc.add_documenter(cls) self.add_directive('auto' + cls.objtype, autodoc.AutoDirective) 會載入 sphinx.ext.autodoc, 但我原本的寫法, 讓 sphinx 透過 __import__ 載入 autodoc, 結果產生兩個不同的物件, 但都是 autodoc, 結果剩下的一些程式操作, 就發生了悲劇。 在 autodoc 裡的這段程式就丟出 exception:if not issubclass(cls, Documenter): raise ExtensionError('autodoc documenter %r must be a subclass ' cls (即 ModuleDocumenter) 真的不是 Documenter 的 subclass, 因為這個 ModuleDocumenter 是其中一個 autodo…

《CPython 源碼剖析》讀書心得 - ch2 - int

PyIntObject展開巨集後的定義typedef struct { Py_ssize_t ob_refcnt; struct _typeobject *ob_type; long ob_ival; } PyIntObject; 基本操作這篇記了加法的實作: 加完後檢查溢位,若溢位的話, 改用大數 PyLongObject。 PyInt_AS_LONG vs. PyInt_ASLong在運算過程中, 視情況會用不同方式取出 ob_ival: 前者是巨集, 沒檢查 type, 速度快 後者是函式, 有檢查 type, 速度慢其它 type 也會看到類似的操作。 immutable不可變的物件有許多好處, 包括可以任意被所有程式共享, 不用擔心造成依賴關係, 會不小心互炸。代價是各項操作後, 時常需要產生新的物件, 可能會拖慢速度。若會用到大量物件的話, 通常會搭配 object pool 減少生成物件的次數, 藉此簡省計算時間, 或是進一步在生成前先檢查是否已存在同樣物件, 有的話直接共享同一物件, 不生成重覆的物件。 在後面的例子會看到, CPython 有用 object pool 處理 int, 但也付出無限擴大記憶體的代價; 另外, CPython 只針對小部份範圍的數字共用物件, 以取得效率平衡。 memory managementintobject.c 開頭寫下為了減少 malloc 次數, 而採取的作法, 以及它造成的問題: /* Integers are quite normal objects, to make object handling uniform.
(Using odd pointers to represent integers would save much space
but require extra checks for this special case throughout the code.)
Since a typical Python program spends much of its time allocating
and deallocating integers, these operations should be very fast.
Therefore we use a dedica…

Sphinx customized theme

官網說明有完整說明, 這裡記個人速記版。 找出 default theme 位置並複制一份出來, 供之後修改:# 找出 default theme 的位置 $ locate default/static /usr/lib/python2.5/site-packages/Sphinx-1.0.7-py2.5.egg/sphinx/themes/default/static /usr/lib/python2.5/site-packages/Sphinx-1.0.7-py2.5.egg/sphinx/themes/default/static/default.css_t /usr/lib/python2.5/site-packages/Sphinx-1.0.7-py2.5.egg/sphinx/themes/default/static/sidebar.js # 切到自己建的 Sphinx 目錄 $ cd docs # 複制 default theme 出來 $ cp -r /usr/lib/python2.5/site-packages/Sphinx-1.0.7-py2.5.egg/sphinx/themes/default MY_THEME 編輯 conf.py 加入:html_theme = 'MY_THEME' ... html_theme_path = ['.'] 這樣之後改 MY_THEME 下的東西即可。 若只需要改 css 的話, 不需複製整個 theme 出來, 可以改 conf.py 裡的 html_static_path, 改用自己的 default.css 覆蓋 default theme 用的 css。照上面的方式找到 default theme 用的 css, 複制出來放到 _static/default.css, 之後再修改這個檔案即可。

小撇步: 直接看指令的原始碼

在 ~/.bashrc 裡這麼寫:function see() { vi `which $1` } complete -c command see 就能打:$ see apt-file 看 apt-file 的內容, 並支援 completion, 可按 TAB 補完指令名稱。

在 Ubuntu 上使用 CUnit + curses 執行 unit test

安裝 sudo aptitude install libncurses5-dev wget -O CUnit-2.1-2-src.tar.bz2 http://downloads.sourceforge.net/project/cunit/CUnit/2.1-2/CUnit-2.1-2-src.tar.bz2?r=&ts=1312211219&use_mirror=nchc tar jxvf CUnit-2.1-2-src.tar.bz2 cd CUnit-2.1-2/ ./configure --enable-curses make sudo make install 這樣會裝到 /usr/local/include/CUnit 和 /usr/local/lib/libcunit.*。
編譯 貼上這裡的範例程式, 存檔為 example.c 註解掉最下方的 CU_basic_run_tests();, 改為 CU_curses_run_tests;, 並在上面加入#include "CUnit/CUCurses.h" gcc example.c -lcunit -lncurses -o example執行 ./example失敗的話, 檢查一下 /usr/local/lib 是否有在 /etc/ld.so.conf 裡, 加進去後執行 /sbin/ldconfig –v 更新設定。細節參考: 《error while loading shared libraries的解決方法》
若不想用 curses 的話, 就用 CU_basic_run_tests。
若確定用不到 curses, 安裝時可以不裝 libncurses5-dev、configure 時可以少掉 --enable-curses。這樣的話, 編譯時也不用加 -lncurses。
不過用 curses 跑還挺炫的說, 會有綠色的 progress bar!! 之後再來看看是否實用。

找出占用 port 的程式

netstat -nap | grep 8000 會找出使用 port 8000 的程式