讀《Efficient C++》疑惑 (轉)
當我們進行開發時,如果程式碼比較少,我們可以很容易的掌握、瞭解的情況,但是當程式碼超過數千行,特別是達到上萬行的時候,我們就很難準確掌握程式的流程,在這種情況下,進行程式碼跟蹤是很重要的一件事情。
程式碼跟蹤技術,對於大多數程式設計師來講,就是定義一個比較簡單的Trace類,將程式的資訊進行輸出,一般是在程式的入口寫一條資訊,在程式的出口寫一條資訊,雖然這是以時間為代價,但是它有助於我們在不使用器的情況下找到問題所在。
最極端的情況就是透過#ifdef開關,徹底消除效能開銷,但是要像開啟/關閉跟蹤,必須重新編譯,顯然程式的最終無法這麼做。所以只有透過動態的與程式通訊來進行跟蹤控制。
首先,為了能夠獲得程式執行時間,我們先自己定義一個簡單的測試效能的類,名字就叫做Timer,實現如下:
class Timer
{
public:
Timer():start(clock()) {}
~Timer() { cout< private:
clock_t start;
};
接下來,我們就要定義一個簡單的跟蹤類Trace,初步實現如下:
class Trace
{
public:
Trace(const string& name);
~Trace();
static bool trace_active;
private:
string theName;
};
bool Trace::trace_active=false;
inline Trace::Trace(const string& name):theName(name)
{
if(trace_active)
cout< }
inline Trace::Trace(const char* name):theName(name)
{
if(trace_active)
cout< }
inline Trace::~Trace()
{
if(trace_active)
cout< }
接下來我們進行測試,先定義一個簡單的:int f(int x) { return x+1; }
先測試不跟蹤的時間開銷:
int main()
{
Timer* time=new Timer;
Trace::trace_active=false;
for(int i=0; i<1000000; ++i) f(i);
delete time;
return 0;
}
輸出時間是30ms。
接下來,我們開啟跟蹤功能: int f(int x) { Trace trace("f"); return x+1; } Trace::trace_active=false;
同時把I/O關閉,再次測試,結果如下:1892ms
這裡我們看到了時間提升了62倍,主要的效能來源就是(1)在建構函式中"f"要轉換成string型別,(2)theName的構造和析構。似乎各自影響了1/3的,是不是這樣呢?
下面,我們取消"f"要轉換成string型別的開銷:增加一個建構函式:
Trace(const char* name):theName(name)
{
if(trace_active)
cout< }
再次進行測試,結果如下(關閉I/O):1690ms
效能的提高似乎並不像我們預期的那樣高,為什麼呢?難大是if(trace_active)影響了測試結果?我們再把這條判斷語句關閉,再次進行測試,結果如下:1646ms。
還是差了一些,並不是1/3的資料,是不是引數傳遞的影響?這次我們把theName也拿掉,看看類本身到底佔用了多少時間,再次測試,結果如下:153ms。
分析以上資料:類本身的引數傳遞等佔用了153ms,if判斷語句佔用了44ms,theName的構造和析構佔用了1493ms,"f"轉換成string佔用了202ms,所以我們的主要目標應該集中在theName上面,下面我們用組合取代聚合,看看效能的變化:
class Trace
{
public:
Trace(const string& name);
~Trace();
static bool trace_active;
private:
string* theName;
};
bool Trace::trace_active=false;
inline Trace::Trace(const string& name)
{
if(trace_active)
{
cout< theName=new string(name);
}
}
inline Trace::Trace(const char* name)
{
if(trace_active)
{
cout< theName=new string(name);
}
}
inline Trace::~Trace()
{
if(trace_active)
{
cout< delete theName;
}
}
測試結果是2682ms,和我們採用聚合相比,時間增加了58.70%,看來在堆上建立開銷的確很大。但是書上說,這時候,時間反而減低了一個數量級,這是我不能夠理解的,如果有誰看過這本書,煩請告知一下,謝謝了!
結論:從上面的分析,我們可以看出對於一個很小的函式,更總的開銷相對來說很大,影響了程式的效能。所以適合內聯的,就不適合跟蹤,Trace物件不應該新增到頻繁使用的小函式中。
注:以上資料是在dev-C++ 4.9.5.0,下,每組資料測試了10次,取平均值得到的。另外,在上面的資料測試過程中,我始終沒有開啟I/O,原因是I/O太消耗時間了,不信,你開啟看看。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-958701/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- [論文解讀] DXSLAM: A Robust and Efficient Visual SLAM System with Deep FeaturesSLAM
- 論文解讀(GCC)《Efficient Graph Convolution for Joint Node RepresentationLearning and Clustering》GC
- Memory-Efficient Adaptive OptimizationAPT
- 閱讀筆記(Communication-Efficient Learning of Deep Networks from Decentralized Data)筆記Zed
- [論文閱讀] Aligner@ Achieving Efficient Alignment through Weak-to-Strong Correction
- JUnit的疑惑
- 【論文閱讀】Informer Beyond Efficient Transformer for Long Sequence Time-Series ForecastingORMAST
- SAP Enables Fast and Efficient Development with New IoTASTdev
- 入門計劃->使用(C++庫)fstream讀寫檔案 (轉)C++
- A tour of Go例程疑惑Go
- 解除程式疑惑 rundll32的作用及應用方法(轉)
- C++:小說閱讀器C++
- C++檔案讀寫C++
- 【C++泛讀總結】C++
- 使用 C++ 讀寫 ExcelC++Excel
- c++ istream 讀取方法C++
- C++中字串讀取C++字串
- C++讀寫檔案C++
- C++的快速讀入C++
- 《高質量C++程式設計指南》讀書筆記(一) (轉)C++程式設計筆記
- "堆"和"棧"的基本概念(C/C++初學者必讀) (轉)C++
- 侯捷對《C++ Primer》《GP&STL》的讀書建議 (轉)C++
- 入門計劃->使用(C++庫)ifstream讀檔案資料 (轉)C++
- JavaScript this 從此不再疑惑JavaScript
- js關於this的疑惑JS
- java 初學者的疑惑!!!Java
- java初學者的疑惑Java
- 對Repository的疑惑
- 初學Java的疑惑Java
- C++ 轉型C++
- The New C++ (轉)C++
- 在Visual C++中使用fopen()函式來讀寫檔案 (轉)C++函式
- C++中的檔案輸入/輸出(2):讀取檔案 (轉)C++
- Deep Hashing Network for Efficient Similarity RetrievalMILA
- SEA-RAFT: Simple, Efficient, Accurate RAFT for Optical FlowRaft
- Unlearn What You Want to Forget Efficient Unlearning for LLMs
- Efficient DevSecOps Workflows with a Little Help from AIdevAI
- C++讀寫檔案操作C++