Cameron Laird 提供了一些有用的示例
這些示例對於很有可能在您自己的應用程序開發中發生的各種性能問題而言
是很合適的模型
性能突破似乎有兩種不同的實現方式
簡單的和困難的
這並非陳詞濫調
這兩者之間的界限極其清晰
當您聽說了某些簡單的方式時
您拍手歎道
噢
對極了
或
太棒了
雖然在許多情況下實現這些方式的第一個應用需要相當聰明的頭腦
但是它們易於理解
另一種方式涉及了仔細的測量
專門的知識和大量的調優工作
這些過程通常是令人痛苦的
也是值得的
要視
本地條件
(比如硬件的具體情況)而定
優秀的程序員可以用
困難
或
簡單
方式進行工作
由於性能對 Linux 程序員而言是非常重要的主題
因此我提供了四個來源於實際(編程)生活中的故事
它們按
困難
和
簡單
方式配成兩對
始終從需求入手
死亡和交稅都是不可避免的
對於開發人員而言
與此差不多同等重要的是仔細考慮需求
這是每種編程都會提到的一個主題
盡管性能的確很重要
但是處理這種需求的最佳方法往往並不是顯而易見的
我經常會碰到一個軟件難題
它大致符合這樣的模式
程序正處於使用之中
它的功能是正確的
但是某個用戶使用了一下
然後報告說它
太慢了
需要加速
某團隊成員很快添加了
監視器
這降低一點性能
但是使用戶能一直知曉長期運行的計算還需多少時間
於是滿意度就增加了
我在
世紀
年代末首次注意到這種現象
此後每十年就可以看到一回
我覺得從某種意義上講自從計算開始它就一直在發生
關鍵並不在於最終用戶容易受騙或者可以被光鮮的
裝飾
轉移注意力
相對我們狹隘
專業的
性能
概念而言
他們只是有更廣泛的目的
在許多情況下
當他們指出計算需要更快一點時
他們真正的意思是他們需要更快更可靠地知道該計算將要進行多久
得知精確的時間信息後
最終用戶可以在計算機延遲期間快樂地安排其它任務
建議參與處理性能的每個人都進行
熱身練習
首先
閱讀或重讀您最喜歡的有關需求管理方面的參考資料
下面的參考資料一節提供了幾個有用的起點
其次
在您的工具箱中放置一些
進度監視器
進度欄
或
秒表
當您發現讓用戶等得太久時可以迅速地將其插入應用程序中
這些根本不用付出太多
如下面這兩個示例所示
兩個倒計時示例
執行一個長時間的計算
同時又要讓用戶知曉其進度
這構成了應用程序設計中一個非常有趣的問題
它是個並發性或
多任務
的實例
許多開發人員都相信
作為正確的解決方案
並發性需要有精巧的機制
特別需要有復雜的線程代碼
其實不然
下面的參考資料一節列出了一篇較早的 developerWorks 專欄文章
我在其中概述了並發性涉及的許多技術
此外
至少自
年以來
基本上已經在所有 UNIX 主機上實現了簡單的並發編程
在
年這一年 ksh 對其
協同進程(co
process)
進行了標准化
如果您將下面清單
中的 ksh 源代碼保存為 ex
ksh
然後運行它
您會看到
倒計時
顯示
十
九
八
等等
然後看到 ksh 子進程的結果
All done
實際運用中
您可能會對長期運行的化學計算或數據庫檢索使用類似這樣的操作
啟動操作作為子進程
但是讓用戶始終知道操作的進展或完成之前還剩多少時間
更新顯示只用了幾行源代碼
清單
示例倒計時顯示的 ksh 源代碼
(echo
This models a long
lasting process
; sleep
;
echo
All done
) |&
for ((i =
; i >
; i
))
do
printf
%
d seconds before completion
\r
$i
sleep
done
read
p line; # Discard the title line
read
p line
echo
echo
Output from the sub
process is
$line
為用戶提供
實時
信息只需要進行適量的編碼
即使基於字符的應用程序也可以做到這一點
如果圖形用戶界面(GUI)更適合您的情況
那也很簡單
許多工具箱都內置了
忙碌
等待
或
進度
顯示
如果您還沒有這樣一個工具箱
那麼幾行 Tk 或另一個新式的 GUI 工具箱就足以制作有點
類似的
倒計時鐘面或進度欄
下面是一個在幾個頁面試用過的
從頭開始做的
示例
清單
示例倒計時顯示的 Tk 源代碼
proc countdown {seconds} {
init
countdown_kernel $seconds
}
proc countdown_kernel seconds {
hands $seconds
if !$seconds return
after
[list countdown_kernel [incr seconds
]]
}
proc draw_hand {angle decorations} {
eval
c create line $::size $::size [get_xy $angle] $decorations
}
proc end_coordinate difference {
set hand_length [expr $::size *
]
return [expr $::size + $hand_length * $difference]
}
proc get_xy angle {
return [list [end_coordinate [expr sin($angle)]] [end_coordinate [expr
cos($angle)]]]
}
proc hands seconds {
catch {
c delete withtag hands}
set twopi
set seconds_angle [expr $seconds * $twopi /
]
draw_hand $seconds_angle
width
tags hands
set minutes_angle [expr $seconds_angle /
]
draw_hand $minutes_angle
width
capstyle projecting
tags hands
}
proc init {} {
catch {destroy
c}
set ::size
set full_diameter [expr
* $::size]
pack [canvas
c
width $full_diameter
height $full_diameter]
set border
set diameter [expr
* $::size
$border]
c create oval $border $border $diameter $diameter
fill white
outline black
}
countdown
這個倒計時顯示了分針和秒針
如圖
所示
其信息內容與前面的程序相同
圖
用 Tk 編碼的模擬倒計時時鐘的外觀
/
/
gif >
請記住
信息可以代替功能
您的最終用戶對應用程序的內部狀態越了解
他們對您的要求就越少
只要讓您的程序顯示它們是如何工作的
就可以解決許多明顯的性能問題
排序很難
前面介紹的是
簡單的
課程
沒有專門的編程背景知識的
平民百姓
也可以理解前面的段落
但是排序卻屬於
困難
這一類
而且這肯定是困難的
Donald Knuth 的一整卷有關計算的經典系列都致力於研究排序和搜索(請參閱參考資料以獲取對 Knuth 撰寫的 The Art of Computer Programming 的評論的鏈接)
結果證明
由於深層次的原因
排序是許多性能難題的核心所在
性能只是大規模計算的問題
人類一次只能理解幾個方面
因此對於那些大得要花掉很長時間才能掌握的問題
我們采用的方式是用某種方式把它們組織起來或使其結構化
排序是這些方式中最常見的一種
可以對已排序列表進行二元搜索而不進行線性搜索
例如
這使得在紐約市電話號簿中進行的手工查找得到了簡化
將一個百萬級大小的問題簡化成一個一百萬的對數(也就是
大約為
)級的問題
那是典型的排序工作
高級算法通常比低級算法快一千倍或更多
值得進行巧妙的排序
但是最聰明的做法就是避免進行整體排序
或者至少將排序僅限於在不受注意的場合進行
這在數據庫管理系統中很常見
其它好處之一就是
它們允許構造
插入時
索引
需要排序結果時
可以直接從索引中讀取
這一操作的代價就是
創建或插入元素的時間稍微有點長
但是如果應用程序具有典型的工作流的話
用戶覺察不到這一點
Knuth 的參考資料描述了其它許多策略
比如用來在特定的條件下加快排序操作的
Boyer
Moore
或
Rabin
Karp
統一這些策略的一個公共原則是
解決通用問題比解決比較特定的問題更容易
數學家對此很熟悉
如果將代數中的常見問題考慮成復數而不是實數時
那麼這些問題就更容易處理
盡管復數算法較難
這就是我對
裝飾
排序
去除裝飾(decorate
sort
undecorate
DSU)
的看法
假定您擁有這樣的數據集
Jane Jones
>
Dan Smith
>
Kim Black
>
From:http://tw.wingwit.com/Article/program/Oracle/201311/17786.html