2014-01-18 112 views
0

有人可以告訴我如何創建一個線程在德爾福2010年將「待機」的數據進行計算(不要終止後,其計算任務)?背景工作線程德爾福2010

我創建了一個程序,通過Indy UDPServer從外部源獲取數據。 IdUDPServer1UDPRead事件收集數據並調用不同的線程(取決於數據的類型),但在調試程序時,我看到線程在計算後被終止,然後再次被創建(線程的創建正在進行時間)。 只要輸入數據的頻率大於CPU(或線程)可以處理的數據(線程完成計算之前數據即將到達),我是否可以創建同一線程的fork線程?


這是我嘗試寫代碼:

procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; 
    AData: TBytes; 
    ABinding:TIdSocketHandle);            
begin 
    form1.panel2.color:=clLime;  
    ParseDelimited(IdUDPServer1.ReceiveString,'&');  
    if (Parsedelimited=1) and (Jvthread1.Terminated=true) then 
    Jvthread1.Execute(self)  
    else if (Parsedelimited=2) and (Jvthread2.Terminated=true) then 
    Jvthread2.Execute(self); 

    Application.ProcessMessages; 
    // i know this command is not very good but by removing this line the 
    //gui is responding //after 2 or 3 sec 
end; 

的問題是,它需要的JVThread1或JVThread2做計算的時候是比輸入數據更大,它是我相信這個問題是由一次又一次創建線程所需要的時間造成的(也許這是一個錯誤的猜測)。儘管如此,通過將傳入的UDP數據緩存到Indy UDPServer可以部分解決這個問題,但是當我試圖關閉UDPServer時,沒有任何事情發生,直到它的緩衝區完全爲空,這大約需要3-4秒。

+0

歡迎來到Stack Overflow。儘管您已經努力在您的問題中包含詳細信息,但如果您還可以包含代碼,那將是一件好事。以下是編寫好問題的指導原則。 http://stackoverflow.com/questions/how-to-ask –

+0

當我輸入我的答案時,我注意到你添加了另一個答案,這真的是一個問題。 (**注意**如果問題的更多信息,請編輯您的問題,如果是不同的問題,請提出一個全新的問題。)關於您問到的問題:「線程安全性」是一個非常具體的話題,睡眠「是完全無關的。然而'睡眠'雖然不是非常糟糕,但通常被認爲是一個可行的解決方法,因爲你正在停止一個固定的時間。如果需要的話,你寧願能夠被觸發醒來。我的答案列出了更好的替代'睡眠'。 –

+0

@TwentyGotoTen我個人對這樣的更高級別的問題沒有問題。 OP不確定哪些選項可用,並需要一般指導。實際計算的代碼僅用於確認已經清楚的內容:方法在計算完成後結束。 –

回答

1

創建線程正在採取一些時間

真。

我可以創建同一線程的線程叉只要輸入數據的頻率更高

這是沒有意義的。您的計算機只能同時執行多個線程(CPU數量)x(一個CPU中的核心數量)。所有其他線程將等待他們的時間片。無論你創建多少個線程 - 只有很少的線程可以執行。而創建更多的線程 - 只會浪費系統資源。

所以正確的方法是我認爲不要終止線程,它計算出數據幀,而是請求下一個工作負載,並在沒有即時作業準備好時進入睡眠狀態。

總的來說,我建議你也看看管道模型:將你的數據分割成幾個階段。 (互聯網) - >輸入隊列 - >(N個工作線程,一些睡眠一些活動) - >半處理數據隊列 - >(N個工作線程,一些睡眠某些活動) - >完全處理的數據隊列 - >(M結果保存線程)

正如我上面所說,N受限於您的總CPU內核數。 M受限於可用的最終存儲。通常它是單個HDD上的單個數據庫,因此M == 1,但存儲可能會分成不同的服務器或不同的磁盤。

如果您的數據是不同種類的,您可以分流,以便某些階段將結果輸出到由不同工作池處理的兩個不同隊列中,並根據數據類型進行判斷。

訣竅是安排一個易於使用的框架,在該框架中,線程很容易進入睡眠狀態,並隨着輸入數據的執行而自動喚醒。 OmniThread庫可能是一個可能的解決方案,因爲你使用德爾福2010年:讀http://robertocschneiders.wordpress.com/2012/11/22/datasnap-analysis-based-on-speed-stability-tests/似乎印地不是爲一個多連接的應用程序優化後http://otl.17slon.com/book/doku.php?id=book:highlevel:pipeline


也。由於UDP是一種無會話協議,因此我希望爲任何新的連接打開一個新的會話,並且可能會顯示類似的性能限制。

我建議你嘗試在不同平臺上設計一個假的服務器,並嘗試重載(DDoS)它來比較不同庫允許的最大吞吐量。 Indy是一個,然後有OverByte ICS和Ararat Synapse,還有Synopse mORMot。如果你想以流水線模式設計你的程序,那麼我認爲你將能夠輕鬆地將任何其他庫的初始TCP/UDP輸入階段切換。但是在編寫代碼的其餘部分之前,也許你能夠證明你的庫最適合你的應用程序目標?但是,您的初始階段是非常簡單 - 只需接收數據並將其放入隊列而不進行分析,讓調度員查看接收的數據類型並將其發送到不同的處理隊列。

+0

非常感謝。但是因爲我是delphi的新手,所以我想問一下: 我該怎麼睡一個Delphi TThread或Jedi JVThread並自動喚醒線程?你能給我一個簡單的編碼例子嗎? 我讀的地方(我認爲在embarcadero網站),在德爾福2010年睡覺線程是不安全的!這是真的嗎? – Dim

+0

我給你在OTL wiki上的例子。它有很多控制工作線程的數據隊列的例子。我不能說d2010是否擅長多線程(d2009很糟糕),但OTL使用自己的管理而不是tthread,嘗試閱讀教程也許會有意義。 –

1

既然你的問題是可以理解的高水平,我會提供一個高層次的答案,它應該指向正確的方向。如果您有更具體的問題,請首先檢查是否有其他人已經提出問題;如果不是的話,隨時可以提出一個新問題。

每當你實現一個線程,你完全可以控制線程的功能。所以是的,如果你的線程執行方法只是簡單地執行一個計算然後結束,你的線程將終止。如果你想保持你的線程激活,只要確保方法不會結束。最簡單的方法是使用while True do;警告把你的線程變成一個簡單的無限循環,實際上是非常差,因爲它引入了一些嚴重的問題。您確實需要一個無限循環來保持線程在多個計算可用時保持活動狀態;不過,您需要額外的代碼才能解決以下問題。

  • 像一個天真的循環只會霸佔你的處理器(哪怕循環什麼都不做)的一個核心。這是浪費資源並可能對其他應用程序產生負面影響。你真正想要的只是線程在實際上有工作時才進行處理;並且否則停止/暫停。
    • 這可以通過使用Windows API調用(或Delphi等效)來告訴線程停止,直到發生其他事情。
    • 請在以下一些閱讀:SleepExWaitForSingleObjectTSimpleEvent
  • 第二個嚴重的問題是,像這樣的循環無法結束優雅。通過優雅地結束,我們的意思是執行方法有一種方法可以在「清理」之後正常退出。否則,如果您強制它在做某件事情的時候退出,它可能會分配資源,鎖或內存,無法釋放。
    • 所以你想在你的循環中改變的第一件事是,而不是while True,你應該使用while not Terminated。這樣,任何引用你的線程的東西都可以設置一個標誌,告訴你的線程必須在它適合的時候立即退出它的循環(從而終止)。
    • 請注意,如果你的線程被暫停(詳見前面的問題),你還必須確保設置該標誌喚醒線程最多實際上檢查的標誌。因此,您可以添加到您較早的閱讀列表中:WaitForMultipleObjects
  • 您必須處理的最後一個問題是獲取新的數據到您的線程,以便它可以執行計算。通常當人們創建線程來執行一次性任務時,創建線程時會傳遞所需的數據。簡單地允許主應用程序更新數據的簡單方法絕對是不好!在計算完成之前,您可能會冒險覆蓋輸入數據;或者更糟糕的是,在計算過程中會覆蓋一些輸入,從而產生不準確和不可預知的結果。
    • 基本上,你需要保持輸入數據結構的列表。無論何時您收到新數據,都會將結構添加到列表中。該線程在處理它們時將從列表中移除項目。 (此列表通常會是一個隊列或FIFO收集。)
    • 每當一個或多個項目添加到隊列中,喚醒事件必須被觸發,線程可以重新開始處理。線程應該在返回睡眠之前處理當前隊列中的所有項目。
    • 注意!您的隊列實現是線程安全的,這是絕對必要的。你不想同時添加和/或刪除來破壞你的內部結構。
    • 推薦閱讀:Message QueuesPostMessage(發送一個消息給一個標準的Windows消息隊列),並Command design pattern

旁註

你似乎關心創建線程的時間開銷。這表明你的計算本身其實很快。這引出了一個問題,你是否真的通過使用單獨的線程來進行計算來獲得任何東西?

你還沒有說你的輸入數據已經是來自不同的線程。因此,如果您的計算涉及多個源線程的數據相關性,那麼確實是是有意義的。我只是提到了這一點,因爲多線程可以加速程序是一種常見的編程錯誤觀念。如果計算速度很快,那麼移動到另一個線程完成相同的工作絕對沒有意義。