2012年2月20日 星期一

[python]map 是什麼?

這是一個說明文。

在 python 的內建函式裡,有一個 map 的函式。
map 不是地圖,若是照執行的意義來解釋,就是映射,白話一點就是一對一對應。

怎說?來看一下官方的說明:

map(function, iterable, ...)

Apply function to every item of iterable and return a list of the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. If one iterable is shorter than another it is assumed to be extended with None items. If function is None, the identity function is assumed; if there are multiple arguments, map() returns a list consisting of tuples containing the corresponding items from all iterables (a kind of transpose operation). The iterable arguments may be a sequence or any iterable object; the result is always a list.

http://docs.python.org/library/functions.html#map

第一句就是定義,「執行 function,把每一個在 iterable 裡的元素當做參數,把每一個結果裝在一個 list 裡,然後回傳。可以假想,map 是長這樣的一個函數(假設 function 只需一個參數):

def map( function_point, iterable):
    result = []
    for i in iterable:
        r = function_point( i )
        result.append( r )
    return result

這種運算常發生嗎?你仔細想想,每當你的任何一段程式是長成這樣(用 c 來舉例):

for ( int i = 0; i < 100; i++)
{
    do_function( i );
}

就可以改寫成:

map( do_function, [0,1,2,…99])

do_function 是本來就要準備的,而 map 是 python 幫你準備好的(其他語言若沒有,則可以自己寫)。帶來的好處有什麼?

  1. 寫法標準化
  2. 縮短程式碼

除此之外,google 告訴你,

可以分散運算!

只要 do_function 執行時,只要傳入引數有關,map 是可以平行運算的。也就是 map 不一定非得像上面所寫從 0 跑到 99,只要你有能力改進 map 這個程式,分散到各台電腦上跑,執行完的結果都會一樣。(http://research.google.com/archive/mapreduce.html)
在 python 裡就有一個現成的多process 的 map 可用。 (multiprocessing.Pool 的 map。http://docs.python.org/library/multiprocessing.html?highlight=multiprocess#multiprocessing.pool.multiprocessing.Pool.map)

Google 還告訴你,他們的系統就是多採用 MapReduce 的 programming model 才能應付如此大量的資料,分散到各電腦上運算又保證結果正確。MapReduce 算不上是 framework,而叫 programming model。如果把 framework 叫做戰略,那 map/reduce 就叫戰術。因為小到每一個程式的每個段落都可能會出現可數迴圈,只要是可數迴圈,不論是否需要結果都可使用這種寫程式的風格。而這種風格在 functional programming 非常常見。大家可以先不知道 functional programming,但 map 好用就應該要常用。

雖然說,python 是 functional language 所以用 map 很自然。
但是其他語言也不是辦不到。
c/c++ 語言,就用 function pointer 來指定 function。
c#, vb .Net 可以用 delegate 來處理。
偷懶一點,參數用 object,嚴格一點,用 template 指定 type。

試試,loop 換成 map 吧!

關於更詳細的 map / reduce 說明及範例,請參閱以下連結
http://code.google.com/edu/parallel/mapreduce-tutorial.html

[python]multiprocessing pool map

最近在微調程式的效能,第一個我想到的,就是從多執行緒來下手。

google 說得好,如果程式裡有用到 map,那麼就可以從 map 開始改。

python 有提供 multiprocessing pool 就不用自己寫 pool。

不過,有幾點要注意:

  1. 這個是 process pool,所以比較吃資源。
  2. 在執行的時候,由於你寫的 py 會被當成 module 讀進執行。
    所以,一定要判斷自身是否為 __main__。也就是要:

if __name__ == '__main__':
    # do something

若第 2 點沒注意到,就會不斷地重覆遞迴執行到當掉。

給個失敗的例子:

import multiprocessing
def m1(x):
  return x*x
pool = multiprocessing.Pool(processes=3)
pool.map(m1,[‘1’,'2’,'3’,'4’])

給個成功的例子:

import multiprocessing
def m1(x):
  return x*x
if __name__ == '__main__':
  pool = multiprocessing.Pool(processes=3)
  pool.map(m1,[‘1’,'2’,'3’,'4’])

如果本來程式就有按 map / reduce 的方式寫,那換成 multiprocess pool 是很快樂的一件事。
試試吧。

2012年2月17日 星期五

[python]logging 有支援 multi-thread

以往,寫 log 都是很直覺,自己開個檔案就寫下去了。

f = open(filename,mode)
f.write(str(datetime.datetime.now())+ " " + string_to_write + "\n")
f.close()

然而,寫久了的確很煩,於是,進一步的,會寫成一個 module 來簡化。

def log(filename,mode,string_to_write):
  try:
    f = open(filename,mode)
    f.write(str(datetime.datetime.now())+ " " + string_to_write + "\n")
    f.close()
  except:
    if f != None:
      f.close()

但是,最近遇到,我的程式開始有 multi-thread,這樣子開檔寫,
有時會漏 log,有時會干擾,像這樣

2012-02-17 23:47:45.211000 DEBUG  doing ('e02_v2.py',)
2012-02-17 23:47:45.211000 DEBUG  doing ('e02_v2.py',)
',)
2012-02-17 23:47:45.211000 DEBUG  doing ('c17_json_v3.py',)
2012-02-17 23:47:52.215000 DEBUG  done ('e02_v2.py',)

這當然不能忍受,但是,要馬上處理這種問題又不會。
還好,python 內建的 logging 是 thread-safe 就可以應付 multi-thread。(還沒辦法處理 multi-process 寫檔案)

logging 最基本的使用方法:

logging.basicConfig(level=logging.DEBUG,
                  format='%(asctime)s %(levelname)s %(message)s',
                  filename=filename,
                  filemode=mode)
logging.debug(log_string)

第 1 行是設定 logging 的 level、每個記錄的格式、檔名、及開檔模式。
第 5 行就是寫 log。

level 預設是 NOTSET, DEBUG, INFO, WARNING, ERROR 及 CRITICAL 等 6 種。
最後面的等級越高。
舉例來說明,設定的等級為 INFO,則 logging.debug 是不會寫入 log 裡,
要 logging.info, logging.warn, logging.error, logging.critical 才會寫入 log 裡。

記錄的格式,可以使用的變數,這裡就不寫,請參考 python 線上手冊。
這裡要提的是,若我們要的,原來沒提供怎辦?
例如,%(asctime)s 寫出來的是:

2012-02-17 23:52:02,157 DEBUG mylog  doing ('e02_v2.py',)

可是我想要這樣,但 time.strftime 不支援 %f

2012-02-17 23:47:52.215000 DEBUG  done ('e02_v2.py',)

這時候可以這樣改,在format 裡加一個變數名,例如 %(curdatetime)s
然後準備一個 d = {'curdatetime' : datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')}
在寫 log 的時候,帶在 extra 的變數裡。logging.debug(log_string,extra=d)
為了方便,我又打包成一個 module 如下:

import datetime, logging
def log(filename,mode,log_string):
  logging.basicConfig(level=logging.DEBUG,
                    format='%(curdatetime)s %(levelname)s %(message)s',
                    filename=filename,
                    filemode=mode)
  d = {'curdatetime':datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')}
  logging.debug(log_string,extra=d)

這樣就不用每次寫 log 都自帶一個 extra 的 dict。

用了 logging,也就不怕 multi-thread 了。

當然 logging 還有很多其他功能。以後不用自己寫了。

http://docs.python.org/library/logging.html#logrecord-attributes

2012年2月13日 星期一

[vbnet]right

有時候,在專案裡,想用 right 卻發生

取得控制項右邊緣和其容器左邊緣之間的距離

那就改用

Microsoft.VisualBasic.Right

也許調整 imports 有用?

2012年2月12日 星期日

[mongodb]MongoDB 的特色

接下來翻譯 www.mongodb.org 首頁的部份。就交待過去。
用大括號括起來的文字是原文,
有些不是很好翻譯的字、詞,
專有名詞,不常見的名詞,
或翻譯字不是很一致的情況,
我就會在譯文後面緊跟大括號原文。

MongoDB (名詞來自 “humongous”) 是一個可擴展{scalable},高效能{high-performance},開放原始碼{open source} 的 NoSQL database。
它是用 C++ 寫的,它的特色是:

  • 文件導向儲存{Document-oriented storage}
    擁有動態架構{schema}的JSON風格文件{JSON-style document} ,簡單有力。
  • 全索引支援{Full Index Support}
    可對任何屬性{attribute}做索引,就跟以前一樣。
  • 重覆{Replication}及高可用性{High Availability}
    可跨 LANs 及 WANs 做鏡像,可用做擴展及安心。(譯:果然,要「信達雅」很難啊,先直譯好了。)
  • 自動分片{Auto-Sharding}
    橫向擴展不影響功能。
  • 查詢{Querying}
    豐富,文件基礎{document-based}的查詢。
  • 快速就地更新{Fast In-Place Updates}
    Atomic modifiers for contention-free performance.(譯:我想想這要怎麼一句話講完…。)
  • Map/Reduce
    靈活的聚合和數據處理。
  • GridFS
    可存任意大小的檔案,不會把你的儲存區搞複雜。
  • 商業支援
    提供企業等級的支援、訓練、顧問服務。