當然效率就不講了(其實已經蠻快的),效率要好其實intel的IPP裡面也提供了intel自己開發的執行緒可以建立(似乎是說效率比較好)
這裡不提Intel的,總之,Windows有很多的DLL(就是Win32 DLL,其實64Bit也可以用啦,只要您作業系統是64bit的),裡面提供無數的函式可以呼叫,
在Visual C#裡面要使用這些函式,必須如下面方式
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int CreateThread(
IntPtr lpThreadAttributes,
UInt32 dwStackSize,
IntPtr lpStartAddress,
IntPtr param,
UInt32 dwCreationFlags,
UInt32 lpThreadId
);
然後您就可以使用這個函式,而在C++ Builder裡面,其實大部分的函式可以直接使用(例如CreateThread),就算不能使用只要去msdn查lib和.h是啥,include進來就可以呼叫了,除了這強大的Win32函式庫,像是STL等很多東西加個對應的.h檔就可以直接使用了,此外C++ Builder本身還封裝一些函式庫,例如您要判斷檔案存不存在,只要FileExists(檔名)就可以了,說實在的挺方便的,
其實像Windows有一些基本結構,例如RECT,BITMAP,HDC...等,他也有一些對應的Class繼承,例如TRect,您可以利用他做一些的處理,而不是只是一個結構,自己還要寫函式去處理細節
總之...很多東西東西都已經實現好了,我們可以直接使用來做處理,當然要是有些功能沒有現成的函式可以處理,那麼我們就必須將底層的Win32函式兜成一個可以用的模組,來呼叫使用,例如要用RS232送字串,我們就利用CreateFile(做法要上網查,網路都有),開啟Com Port,接收或送字串,要是要網路功能,其實他有Indy的套件可以使用,但是如果要自己用Win32函式庫兜功能呢,也是可以的,總之要上網研究一下,網路上有些程式片段只要再改一下,就可以直接使用了
總之就是說有很多函式啦,上萬個,但是其實我們做案子是有分領域的,例如做網路的,那你就只要會網路那塊的函式,做系統整合的,他有一些基本的系統整合相關的函式,原則上會您那個領域的就好,並不是說要將一萬多個函式通通摸過
很多東西上網查都有,但是要兜起來能動說實在的也不太容易,要Try很久,總之就是慢慢學習了
另外就是要會使用lib和DLL,像我做系統整合的(AOI光學檢測),往往會用到一些設備的函式,這時候通常廠商舊提供lib或DLL,並給您他的.h,這時候我們就必須用動態連結DLL的方式,來讓我們可以使用他們提供的函式,又或者是使用ImportLib轉換成C++ Builder能用的Lib來使用DLL,當然這裡就不講這個,總之先提個概念就是了
我們寫一個程式,除了呼叫函式外,就是要寫一個高效能的軟體,
最基本的要知道我們電腦一些元件的速度
CPU>L1 Cache>L2 Cache>L3 Cache>Memory>硬碟>隨身碟>外部設備,
這其實計概上有寫,實際您怎麼確定CPU是最快的呢,其實我們有軟體方法可以測,
例如我寫個For迴圈,裡面就是1+到n,這時候通常只在快取和CPU上跑,您用計算時間的函示去量他的時間(clock(),方法請上網找),
而我們要測記憶體,就是使用memcpy,您就做兩個大一點的陣列,利用memcpy在for迴圈裡面做,您會發現相同指令數,他會比較久,要是您在for迴圈做檔案存取,那又會更久了
下面是例子:
CPU&Cache
double k = 100000000;
double n = 0;
for(double i = 0;i < k; ++i)
{
++n;
}
long end = clock();
double time_ = (end - start) / CLOCKS_PER_SEC;
ShowMessage(time_);
這裡需要561ms
Memory存取
int a[1000];
int b[1000];
long start = clock();
double k = 1000000;
double n = 0;
for(double i = 0;i < k; ++i)
{
memcpy(a,b,1000*sizeof(int));
}
long end = clock();
double time_ = (end - start) / CLOCKS_PER_SEC;
ShowMessage(time_);
我for迴圈還比較少就要9.36秒
硬碟存取
FILE* file_ = fopen("c:\\a.txt","w");
long start = clock();
double k = 50000;
double n = 0;
for(double i = 0;i < k * 1000; ++i)
{
fprintf(file_, "%d", i);
}
long end = clock();
fclose(file_);
double time_ = (end - start) / CLOCKS_PER_SEC;
ShowMessage(time_);
由於跟記憶體複製比,所以複製長度1000要做1000次,所以我乘上1000
這要20秒
外部設備(就更久,其實我知道的就只有網路和RS232,總之比較久就是了)
當然硬碟還有SSD(固態硬碟)和一般硬碟,誰比較快,您就用windows複製大型檔案看看就知道了,就是從SSD複製到SSD,硬碟複製到硬碟,
總之,假設是一個指令,越是低端的設備會越慢,這個知識牽扯到我們寫程式效率的問題,假設在for迴圈裡面存取多次低端設備,會慢很多,通常假設沒必要,for迴圈內是不處理硬碟存取的,當然這種事情很少發生,
還有一種東西也是比較慢的,也就是GDI+指令
GDI+是圖形設備介面,他的指令丟在for迴圈裡面跑也很慢,不只是GDI+指令,VCL的屬性設定或讀取也是
long start = clock();
double k = 50000;
double n = 0;
for(double i = 0;i < k * 1000; ++i)
{
fprintf(file_, "%d", i);
}
long end = clock();
fclose(file_);
double time_ = (end - start) / CLOCKS_PER_SEC;
ShowMessage(time_);
由於跟記憶體複製比,所以複製長度1000要做1000次,所以我乘上1000
這要20秒
外部設備(就更久,其實我知道的就只有網路和RS232,總之比較久就是了)
當然硬碟還有SSD(固態硬碟)和一般硬碟,誰比較快,您就用windows複製大型檔案看看就知道了,就是從SSD複製到SSD,硬碟複製到硬碟,
總之,假設是一個指令,越是低端的設備會越慢,這個知識牽扯到我們寫程式效率的問題,假設在for迴圈裡面存取多次低端設備,會慢很多,通常假設沒必要,for迴圈內是不處理硬碟存取的,當然這種事情很少發生,
還有一種東西也是比較慢的,也就是GDI+指令
GDI+是圖形設備介面,他的指令丟在for迴圈裡面跑也很慢,不只是GDI+指令,VCL的屬性設定或讀取也是
例如:
long start = clock();
double k = 10000;
int n = 0;
for(int i = 0;i < k; ++i)
{
n += i % 1000;
//Height = i % 1000;
}
long end = clock();
double time_ = (end - start) / CLOCKS_PER_SEC;
ShowMessage(time_);
這只要0秒
long start = clock();
double k = 10000;
int n = 0;
for(int i = 0;i < k; ++i)
{
//n += i % 1000;
Height = i % 1000; // 設定Form的高,由於設超過螢幕解析度,他會pass調指令,所以這裡%1000,保證他可以下10000次設定VCL元件的指令
}
long end = clock();
double time_ = (end - start) / CLOCKS_PER_SEC;
ShowMessage(time_);
您會發現只設定Form的高10000次要3.3秒
我們必須知道一些基本的知識,不然是不能寫出高效能的程式的,這邊只是稍微提到,並不深入(其實我也沒全部了解),總之,通常當您的處理太慢時,就必須要做profile(時間分析),看把哪裡mark掉會比較快,再想辦法改寫,使的功能正常外,效能又比較高
當然有時候會為了節省程式碼,一次執行很多多餘的設定畫面VCL物件的指令,這又是另一個問題了,這關於寫Code的速度,以及管理上的方便,有時必須這麼做
但是在實現功能時,通常要注意上面舉的例子的問題,這跟設定畫面VCL物件無關
再來一般近代的程式,要是所有運算都在主執行處理,畫面會卡住,甚至點個幾次就停止回應了,所以其實一個不會當掉的程式,必須把運算量大的都丟到背景執行緒做,C++ Builder有提供TThread,而如果您不用這個就必須使用CreateThread來建立執行緒,當然Win32最近好像又多了ThreadPool及Command Thread這有空可以研究一下,總之運算量大的都要丟到背景就是了
而Windows程式有一個Windows訊息傳遞的寫法必須要會,當您丟到背景去處理運算後,處理結果要秀出到畫面,必須呼叫主執行緒跑(背景執行緒不能動到跟UI有關的東西),這裡不講這個,總之這也是必須要會的,
最後就是Wndproc是處理Form的消息的地方,當您送一個訊息給Form,他會被Wndproc所處理,這裡的寫法很重要,後面有時間會提到這裡,這裡只是簡單寫一下而已
這裡會附上面的例子,您可以用C++ Builder打開測試看看
https://drive.google.com/open?id=0B6u5oifJv3EKOWFGdHZEdDl1cms
long start = clock();
double k = 10000;
int n = 0;
for(int i = 0;i < k; ++i)
{
n += i % 1000;
//Height = i % 1000;
}
long end = clock();
double time_ = (end - start) / CLOCKS_PER_SEC;
ShowMessage(time_);
這只要0秒
long start = clock();
double k = 10000;
int n = 0;
for(int i = 0;i < k; ++i)
{
//n += i % 1000;
Height = i % 1000; // 設定Form的高,由於設超過螢幕解析度,他會pass調指令,所以這裡%1000,保證他可以下10000次設定VCL元件的指令
}
long end = clock();
double time_ = (end - start) / CLOCKS_PER_SEC;
ShowMessage(time_);
您會發現只設定Form的高10000次要3.3秒
我們必須知道一些基本的知識,不然是不能寫出高效能的程式的,這邊只是稍微提到,並不深入(其實我也沒全部了解),總之,通常當您的處理太慢時,就必須要做profile(時間分析),看把哪裡mark掉會比較快,再想辦法改寫,使的功能正常外,效能又比較高
當然有時候會為了節省程式碼,一次執行很多多餘的設定畫面VCL物件的指令,這又是另一個問題了,這關於寫Code的速度,以及管理上的方便,有時必須這麼做
但是在實現功能時,通常要注意上面舉的例子的問題,這跟設定畫面VCL物件無關
再來一般近代的程式,要是所有運算都在主執行處理,畫面會卡住,甚至點個幾次就停止回應了,所以其實一個不會當掉的程式,必須把運算量大的都丟到背景執行緒做,C++ Builder有提供TThread,而如果您不用這個就必須使用CreateThread來建立執行緒,當然Win32最近好像又多了ThreadPool及Command Thread這有空可以研究一下,總之運算量大的都要丟到背景就是了
而Windows程式有一個Windows訊息傳遞的寫法必須要會,當您丟到背景去處理運算後,處理結果要秀出到畫面,必須呼叫主執行緒跑(背景執行緒不能動到跟UI有關的東西),這裡不講這個,總之這也是必須要會的,
最後就是Wndproc是處理Form的消息的地方,當您送一個訊息給Form,他會被Wndproc所處理,這裡的寫法很重要,後面有時間會提到這裡,這裡只是簡單寫一下而已
這裡會附上面的例子,您可以用C++ Builder打開測試看看
https://drive.google.com/open?id=0B6u5oifJv3EKOWFGdHZEdDl1cms
沒有留言:
張貼留言