如果您的OTL任務需要加載符合條件的企業的排序列表:
// create and open query to fetch list of companies
while not qryCompanies.Eof do begin
C := TCompany.Create;
try
C.LoadFromDataset(qryCompanies);
Companies.Add(C);
except
C.Free;
raise;
end;
qryCompanies.Next;
end;
C
是一個公司的業務對象。它可能由對象實現(TCompany
)或接口(ICompany
)。 Companies
是TList<TCompany>
或TList<ICompany>
。在任務結束時,你的公司的名單發送給VCL線程:
Task.Comm.Send(TOmniMessage.Create(MSGID_LIST_OF_COMPANIES, Companies));
在形式要顯示你處理otlEventMonitor
實例的OnTaskMessage
事件正在監視你的任務企業名單:
procedure TListBaseFrame.otlEventMonitorTaskMessage(
const task: IOmniTaskControl);
var
MsgID: word;
MsgValue: TOmniValue;
begin
task.Comm.Receive(MsgID, MsgValue);
Assert(MsgValue.IsInterface);
if fLoaderTask = task then begin
SetLoadedData(MsgID, MsgValue.AsInterface); // or MsgValue.AsObject);
fLoaderTask := nil;
end;
end;
公司列表替換以前的列表,並可以顯示在網格中。
同樣,您可以返回一個公司對象/界面進行顯示和編輯。
兩件事情是值得我們思考:
如果你至今最好的對象接口,編寫多線程程序可能是一個理由重新考慮。如果您在後臺線程中創建對象,然後將它們傳遞給VCL線程並在後臺線程中忘記它們,則對象可能會正常工作。然而,我發現通過在應用程序中緩存對象以及僅從數據庫加載尚未加載或已更改的記錄,可以獲得更好的性能。我所有的表都有變化指數(64位整數,時間戳可能工作以及)連接到它,那就是改變了每次更新。相反,執行
select * from foo where (...) order by (...)
的我只執行一個
select id, change_index from foo where (...) order by (...)
然後在高速緩存中檢查是否有相同的ID(主鍵)和變化指數已經存在,如果這樣返回緩存的對象對象,並且只有在不創建新業務對象並加載所有列的情況下。
但如果緩存中的對象,你將不得不從多個線程,和所有權問題對它們的引用很快得到那麼複雜,基於引用計數的生命週期管理是保持清醒的唯一途徑。在這方面使用接口而不是對象有很多幫助。
添加同步對象到每個業務對象是必要的,如果多個線程可以同時訪問它們。這當然是可能的,但可能會引入額外的複雜性和潛在的僵局。如果您將業務對象實現爲不可變的,那麼根本不需要鎖。我越來越多地使用這種方法,雖然它需要一些適應它,但它可以簡化很多事情。
完美!這正是我錯過的......將結果轉移到其他線程的方式。 非常感謝! – Holgerwa 2010-02-21 13:12:46
+1很好的答案! – jpfollenius 2010-02-21 15:23:02
像往常一樣好的答案! – gabr 2010-02-21 15:45:52