boost.png (6897 bytes) Timer 庫

Timer庫提供了兩個頭文件和三個類:

頭文件 功能
timer.hpp timer 測量流逝的時間。
progress.hpp progress_timer 使用timer類測量流逝的時間,在析構的時候顯示時間。
progress.hpp progress_display 顯示出當前的進度。

設計這些類,僅僅出於這樣的考慮——它們的主要目的是用於計時和報告程序員們的測試程序或者批處理作業的進度。這些進度指示類的說明文檔是以概括性的語言描述的,這樣使得其他形式的實現(比如圖形用戶界面)可以融入進來。

timer類

Timer類用於測量流逝的時間。對於那些小型的計時任務,它通常都很方便。相比較依賴C標準庫的clock()函數那未知的準確度和精密度, timer提供的實現具有適度的可移植性。在timer本身的實現裡面,最大可測量的時間長度大概只有596.5小時(甚至更短)。由於這些限制,不能指望這個timer類非常的健壯(robust),並且也不應該使用在有這方面考慮的任務上。

Synopsis 簡要聲明

#include <boost/timer.hpp>
namespace boost {
class timer {
public:
timer(); // 執行之後: elapsed()==0
// compiler generated copy constructor, copy assignment, and dtor apply編譯器生成的拷貝構造函數、拷貝賦值函數、和析構函數
void restart(); // 執行之後: elapsed()==0
double elapsed() const; // 以秒為單位,返回流逝的時間

double elapsed_max() const; // 返回 elapsed() 的最大估計值
// 關於可移植性的警告:在某些系統上面,std::clock_t類型溢出或者重置,這樣elapsed_max()可能會返回一個非常大的值。

double elapsed_min() const; // 返回 elapsed() 的最小值
}; // timer
} // namespace boost

Exception safety 異常安全

構造函數可能會拋出 std::bad_alloc 異常。 其他的成員函數都不會拋出異常。 

Future directions 今後的方向

Ed Brey需要一個函數來確定elapsed函數可能返回的最大值,但是卻沒有一種方式來讓它具有可移植性。這個問題已經在致力於擴展的C語言時間函數功能 的(extended time functionality)工作組裡面提出。可能未來幾年內會有解決方案。現在,elapsed_max() 提供了一個近似的功能。

progress_timer類

progress_timer類自動地測量流逝的時間,並且析構的時候在一個適當的地方以一種適當的形式,顯示一個流逝了多少時間的消息。它所提供的實現默認是以字符的顯示方式輸出到 std::cout。

progress_timer類通常用於對程序的執行計時。你可以像這樣簡單的使用它:

#include <boost/progress.hpp>
int main()
{
progress_timer t; // 開始計時
// 做一些別的事情 ...
return 0;
}

這段代碼就會產生類似下面這樣的輸出:

1.23 s

注意"s"是國際單位制(System International of Units)對秒的官方縮寫。

Synopsis 簡要聲明

#include <boost/progress.hpp>
namespace boost {
class progress_timer : public timer, noncopyable {
public:
progress_timer();
progress_timer( std::ostream& os ); // os只是一個提示;具體的實現可能會忽略掉
~progress_timer();
}; // progress_display
} // namespace boost

Exception safety 異常安全

構造函數可能會拋出 std::bad_alloc 異常。其他的成員函數都不會拋出異常。 

progress_display類

progress_display類在適當的地方以適當的形式顯示出相對於預設目標的當前進度。這可以讓用戶知道一個程序是否正在進展之中。

比如,如果要在叫一個做big_map的std::map<>容器上進行一個很耗時的計算,下面的代碼就可以顯示出當前的進度:

  progress_display show_progress( big_map.size() );
for ( big_map_t::iterator itr = big_map:begin();
itr != big_map.end(); ++itr )
{
// 進行計算
...
++show_progress;
}

在70%的元素被處理完之後,顯示出來的效果如下所示:

0%   10   20   30   40   50   60   70   80   90   100%
|----|----|----|----|----|----|----|----|----|----|
************************************

Synopsis 簡要聲明

#include <boost/progress.hpp>
namespace boost {
class progress_display : noncopyable {
public:
progress_display( unsigned long expected_count );
// 效果: restart(expected_count)

progress_display( unsigned long expected_count,
std::ostream& os, // os只是一個提示;具體的實現可能會忽略掉
const std::string & s1 = "\n", // 行首字符串(leading strings)
const std::string & s2 = "",
const std::string & s3 = "" )
// 效果: 保存行首字符串(leading strings)的一份拷貝,然後restart(expected_count)

void restart( unsigned long expected_count );
// 效果: 用三行顯示合適的比例,並且每行分別以從構造函數傳入的本地拷貝的s1, s2, s3的開頭。
// 執行之後: count()==0, expected_count()==expected_count

unsigned long operator+=( unsigned long increment )
// 效果: Display appropriate progress tic if needed.
// 執行之後: count()== original count() + increment
// 返回值: count().

unsigned long operator++()
// 返回值: operator+=( 1 ).

unsigned long count() const
// 返回值: The internal count.

unsigned long expected_count() const
// 返回值: The expected_count from the constructor.

}; // progress_display
} // namespace boost

Exception safety 異常安全

除了count()和expected_count()之外的所有的成員函數都會有輸出,因此理論上就有可能拋出異常。在實際使用中,異常被拋出的可能性非常小,當然異常的拋出也可能意味著問題的嚴重性。注意這裡沒有顯示的析構函數,因此析構函數拋出異常是不可能的。

History 追本溯源

這些類派生自那些一直被程序員們認為是有用的舊的C++和C的功能。通過Boost的郵件列表,Reid Sweatman提議把具有更寬廣使用範圍的計時器類(timer)同更具有目的性的進度指示類(progess)分開。Sean Corfield提議允許輸出到任意的流(ostream)。Dave Abrahams, Valentin Bonnard, Ed Brey, Andy Glew和Dietmar Kühl也提供了有用的註釋。Ed Brey提議增加timer::elapsed_max()方法。John Maddock提議增加timer::elapsed_min()方法。Toon Knapen提議使用可選的行首字符串(leading strings),來允許對進度的顯示做標注。

Rationale 基本原理

早期timer類的版本將實現的文件(與頭文件)分隔開來。對那些不願意編譯庫的用戶來說會產生問題,在編譯動態鏈接庫(DLL)的時候出現困難 (由於使用了其他的庫,這些庫反過來又帶來了明顯的編譯器缺陷),使得這些類即使是在明顯適用的情況下也不能使用。因此所有的實現都被放到了內聯 (inline)代碼裡。

也有人要求加入特定平台的實現,以便可以使用那些操作系統提供的按常理應該是高性能的計時器API。John Maddock提交了一份使用Win32 API的實現。測試顯示儘管這些計時器的精確度高,延時有時候卻比std::clock()函數要大得多,而這是非常糟糕的。更進一步講,使用Win32 API的結果非常依賴於編譯器(測試過Mircosoft和Borland的)和操作系統的版本(Windows NT、Windows 95等等)。std::clock()函數更加可靠,因此保留在這個平台上作為它的計時器API。


© Copyright Beman Dawes 1999.
Distributed under the Boost Software License, Version 1.0. See www.boost.org/LICENSE_1_0.txt

Revised November 07, 2007