第一節:初識多線程
1.爲何要學習多線程編程?
多線程(多個線程同時運行)編程,亦可稱之爲異步編程。
有了多線程,主界面纔不會由於耗時代碼而形成「假死「狀態。
有了多線程,才能使多個任務同時執行,最大化利用CPU資源,提升效率。
在安卓編程中,要求必須是多線程,主界面中的代碼只要耗時幾秒鐘,就會觸發 ANR 錯誤。
多線程編程纔是
工做中的常態。
多線程是必須掌握的!越早越好!
2.網絡上 delphi 多線程 Demo 的誤區
採用 API 來實現多線程。難度過高,尤爲是用指針來傳參數,不適合初學者。
用訪問界面來舉例,出發點就錯了。多線程最不擅長的就是操做UI。
網上流行的 demo 就是弄個大循環,再來一個 TextOut 輸出。
結果又不得不加上 canvas.Lock, 真是夠折騰。
3.主線程的定義
假設,一個EXE程序,擁有一個 FrmMain (TForm)。
FrmMain 上面有一個 Button1 (TButton) ,一個Edit1 (TEdit)以及一個 Timer1 (TTimer) 。
那麼,咱們一般把界面(UI)定義爲主線程,即 FrmMain 就是主線程。
Button1 的 OnClick 事件中的代碼運行於主線程時空。(本教程均統必定義
線程時空一詞)
使用者在 Edit1 中的輸入操做也是主線程時空。
Timer1 的 OnTimer 事件中的代碼也運行於主線程時空。
請注意:初學者最容易把 OnTimer 事件誤認爲是多線程時空。
4.普通編程與多線程編程的區別
// 普通編程
function
Accumulate(num:
integer
):
integer
;
var
i:
integer
;
begin
result:=
0
;
if
num<
1
then
exit;
for
i:=
1
to
num
do
result:=result+i;
end
;
// 在 Button1 的 OnClick 事件中編寫以下代碼:
var
n,Total:
integer
;
begin
n:=
100
;
Total:=Accumelate(n);
// 等待計算結果,假設計算須要5分鐘,此處就得等待5分鐘。
// 這5分鐘內,界面是沒法訪問的,是假死的。
// 計算完成,獲得結果 Total=5050;
DoSomeThing;
//接着執行此句。
end
;
|
// 多線程編程,此爲計算線程類
unit
uAccumulation;
interface
uses
Classes;
type
TAccumulationThread =
class
;
TOnAccumulated =
procedure
(Sender: TAccumulationThread)
of
object
;
TAccumulationThread =
class
(TThread)
protected
procedure
Execute; override;
public
Num:
integer
;
Total:
integer
;
OnAccumulated: TOnAccumulated;
end
;
implementation
procedure
TAccumulationThread
.
Execute;
var
i:
integer
;
begin
inherited
;
Total :=
0
;
if
Num >
0
then
begin
for
i :=
1
to
Num
do
Total := Total + i
end
;
// 當計算完成後,就調用 OnAccumulated 通知調用者
if
Assigned(OnAccumulated)
then
OnAccumulated(self);
end
;
end
.
|
寫代碼請用英語命名,用正確的單詞,時態。切記,很是重要!
// 調用多線程
// 在FrmMain 中定義 OnAccumulated 事件函數
Procedure
TFrmMain
.
OnAccumulated(Sender:TAccumulationThread);
var
sum:
integer
;
begin
// 當計算完成時,計算線程就調用本事件函數。
// 咱們在這裏就獲得了計算結果
sum:=Sender
.
Total;
// 由於這裏是線程時空,不能直接把 sum 的值顯示到界面上。
// 如何正確顯示,將下一章節中講解。
end
;
// 在Button1 的OnClick 事件中編寫下面的代碼
var
thd:TAccumulationThread;
begin
// 此處爲主線程時空。
thd:=TAccumuationThread
.
Create(
true
);
thd
.
OnAccumulated=Self
.
OnAccumulated;
// Self 指是 FrmMain.
thd
.
Num:=
100
;
thd
.
Start;
//啓動線程,在線程時空中執行 Execute 中的代碼。
// start 當即返回並執行下一條代碼 DoSomeThing;
// 此時,就有兩個線程在同時執行。
// 1.主線程,也就是此處運行的時代碼。
// 2.計算線程,也就是 Execute 中的代碼,這些代碼此時運行於多線程時空。
// 因爲是兩個線程並行在執行,故此處 DoSomeThing 立刻能夠執行。
// 界面也不會假死
DoSomeThing;
end
;
經過比較,彷佛看出多線程要寫更多的代碼?要用事件來傳遞結果來給調用者?
其實都否則,這兩點均是面向對象(OO)寫法,與線程類無關。
最大的不一樣是:
異步執行,把耗時的計算任務放了入另外一個線程時空!
多線程帶來了效率,同時也帶來了更多的麻煩。欲知後事如何,且聽下回分解。