熟練使用小工具讓自己從機械工作中解脫
一直以來我都相信熟練地使用各種小工具能大大提升生產力,把人們從無聊的機械工作中解脫出來。昨天我就在做一些無聊的機械工作,正好這些技能就派上了用場。我覺得可以把它分享出來,或許就會有年輕人被安利了。
無聊的機械工作
我們寫了一個資料庫,昨天我要做的事情是在不同的實驗設定下運行標準的 TPC-C 測試。我們用的 TPC-C 測試程序是 py-tpcc,每次運行它會產生如下格式的結果:
==================================================================================================Execution Results after 60 seconds-------------------------------------------------------------------------------------------------- Executed Time (μs) Rate DELIVERY 722 30254463.91105652 23.86 txn/s NEW_ORDER 8680 21493624.687194824 403.84 txn/s ORDER_STATUS 765 401196.0029602051 1906.80 txn/s PAYMENT 8276 5778122.663497925 1432.30 txn/s STOCK_LEVEL 774 1124487.1616363525 688.31 txn/s-------------------------------------------------------------------------------------------------- TOTAL 19217 59051894.426345825 325.43 txn/s
我首先要做的就是跑實驗,然後把上面 txn/s 前面的這6個數字粘貼到 Google Docs 上。同一個實驗需要跑多次,這樣我們才能給出一個誤差的範圍。再加上有若干組不同的實驗設定,其實數據點數還蠻多的。
一開始我的做法就是跑實驗,然後兩個窗口不停切換複製粘貼。做了兩三次之後覺得實在是太憋屈了,感覺整天的時間都要耗在這上面。大好時光竟然來做這個?還不如睡覺呢!於是我決定稍微花點時間讓它自動化進行。
自動運行實驗
第一步就是要讓實驗能夠自己運行,然後把結果保存好。花5分鐘時間寫好這麼一個小腳本,保存成 run-all.sh:
run_mongodb() { clients=$1 cd ~/tmp/apavlo-pytpcc/pytpcc ./tpcc.py --config=mongodb.config --duration 60 --clients $clients --warehouses 1 mongodb >> result-w1-mongodb-denorm-$clients.txt printf "use tpcc
db.dropDatabase()
" | mongo sleep 10}run() { run_mongodb "$@" run_mongodb "$@" run_mongodb "$@" run_mongodb "$@" run_mongodb "$@"}run 1run 2run 5run 10
這裡我定義了兩個函數:run_mongodb 會運行一次實驗,實驗的參數實際上只有一個——客戶端數量——通過 $1 傳入。實驗的結果每次會追加到一個文本文件裡面,這個文本文件的文件名對於同樣的實驗參數是一樣的,也就是說,同樣的實驗會把結果保存在同一個文件中。另一個函數 run 就很簡單了,把同樣參數的實驗跑5遍。最後寫上我們想要運行的實驗參數,這裡寫了分別測試1個、2個、5個和10個客戶的情況。
運行 bash run-all.sh,看一下沒出什麼問題,就可以去玩耍了。
提取實驗數據
做了頓飯回來實驗就跑好了,並且每組實驗都保存在各自的文件中。下一步的工作就是把實驗數據粘貼到 Google Docs 上面。這裡的基本思路是,把數據提取出來,轉換成 CSV 格式。這樣一來就可以用表格處理軟體打開 CSV 文件,複製,然後粘貼到 Google Docs 上面了。
觀察一下 pytpcc 的輸出,我們會發現要把其中的數據轉換成 CSV 格式還是很簡單的:
- 從文件一行一行讀入
- 按照空白字元分割成若干個部分
- 如果第一個部分不是 DELIVERY 等6個關鍵詞,就跳過
- 如果是的話,把分割後的第4個部分取出來,這就是我們需要的數據
- 特殊處理一下 TOTAL,在遇到這一行的時候我們在輸出裡面添加一個換行,表示一次實驗結束了
很容易地就可以寫出下面的 Python 代碼:
import syswith open(sys.argv[1]) as f: for line in f: split = line.strip().split() if not split: continue if split[0] in [DELIVERY, NEW_ORDER, ORDER_STATUS, PAYMENT, STOCK_LEVEL]: sys.stdout.write(split[3]) sys.stdout.write(,) elif split[0] == TOTAL: sys.stdout.write(split[3]) sys.stdout.write(
)
非常幸運的是,昨天我寫下這個代碼之後,直接運行就得到了我想要的結果:
$ python3 read_result.py ~/tmp/apavlo-pytpcc/pytpcc/result-w1-mongodb-denorm-10.txt10.15,52.02,162.75,103.98,65.60,62.6410.14,52.74,158.00,105.61,64.93,63.3410.11,52.25,159.85,104.15,64.26,62.8010.32,52.55,152.49,105.50,65.46,63.5510.20,52.62,161.14,105.56,65.41,63.47
下面的事情就是對所有的結果都運行一遍這個小腳本,用 find 就行了:
$ find . -name result-*.txt -print -exec python3 read_result.py {} ;./result-mongodb-tx-5.txt6.56,87.02,67.13,56.97,43.89,48.886.86,89.11,62.66,40.82,44.81,44.416.51,88.26,58.73,57.49,44.01,48.433.08,90.08,66.50,58.72,45.89,35.546.48,88.07,63.08,58.27,43.21,49.31./result-mongodb-tx-2.txt8.06,97.98,71.89,69.76,53.31,58.848.30,101.53,55.65,69.67,53.62,60.428.01,99.31,77.18,68.49,52.79,58.757.97,100.58,75.25,69.49,52.39,59.363.99,99.87,57.47,51.13,56.04,41.89...
值得注意的是,find 的輸出是無序的,對我們來說要粘貼到 Google Docs 上面匯總當然是希望有序的比較好整理。第一反應沒有想到特別簡練的命令來解決這個問題,不過簡單拼湊一下也是很容易:
for x in `find . -name result-*.txt -print | sort -V`; do echo $x; python3 read_result.py $x; done
也是一行就搞定。解釋一下:find . -name result-*.txt -print | sort -V 先執行 find 找出所有符合要求的文件,然後管道傳給 sort 進行排序,其中 -V 可以讓 result-10.txt 排到 result-2.txt 後面,這樣我們就得到了有序的文件名列表了。外面是一個循環,依次遍歷文件名列表,把當前文件名放在 $x 中,在循環體中先列印出文件名再執行 python 腳本。
把上面命令的輸出保存成文件,並把後綴命名為 .csv,就可以愉快地用表格軟體打開啦。
處理實驗數據
把上面數據貼到 Google Docs 之後,我把其中 TOTAL 的那一列數據複製下來。現在我希望先把數據5個5個地分組(也就是同一個設定的多次試驗)。說實在的,我雖然現在用習慣了 Sublime Text,但是我還真不知道怎麼在裡面實現這個效果。不過沒關係,我可以回到老朋友 Vim,用宏可以輕鬆地解決:
- qa 開始宏錄製,保存成宏 a
- $ 跳到行末
- Ctrl + v 開始塊選擇
- jjj 選擇4行
- Shift + a 在每行的行尾插入
- , 我想插入逗號
- ESC 回到普通模式
- V 開始行選擇
- jjjj 向下選擇5行
- J 合併這5行
- j 走到下一行(也就是下一組數據的起點)
- q 退出宏錄製
- 34@a 重複執行34次宏 a
這樣數據按照每行5個分好了。後面我就回到 Sublime Text 裡面,把它處理成 Python 能處理的格式。同樣,塊選擇依然是一個非常好用的功能。
https://www.zhihu.com/video/906848484345401344 https://www.zhihu.com/video/906848530294009856
最後,簡單地調用一下 matplotlib 就可以把圖畫出來了。
#!/usr/bin/env python3import numpy as npimport matplotlib.pyplot as pltimport collectionsDATA = collections.OrderedDict([ ...])plt.style.use(ggplot)plt.xlabel(The Number of Concurrent Clients)plt.ylabel(Transactions per Second)for i, (title, data) in enumerate(DATA.items()): xs = np.array([t[0] for t in data]) ys = np.array([np.mean(t[1]) for t in data]) es = np.array([np.std(t[1]) for t in data]) bar = plt.errorbar(xs, ys, yerr=es, label=title)plt.legend()plt.tight_layout()plt.savefig(tpcc.pdf)
總結
- 善用各種工具可以提升工作效率,甚至熟悉快捷鍵也很重要(當然,要到熟練掌握還是需要不斷的練習的)
- 不需要要求自己精通每一個工具,只需要懂得常用的幾個用法就好
- 把不同的工具組合在一起可以發揮巨大的功效
首發於博客:熟練使用小工具讓自己從機械工作中解脫
推薦閱讀:
※為什麼 Linus Torvalds 不願意將 Linux 變成 GPLv3 授權?
※有沒有學習Linux比較好的入門書籍?
※為什麼 Linux 內核中不經常使用 typedef?
※用作生產環境伺服器,FreeBSD和CentOS相比有哪些優劣勢?
※route命令與iptables實戰