2013-06-02 23 views
2

使用OmniThreadLibrary和Delphi XE4,我希望運行多個線程來處理後臺數據,爲我現有的代碼增加速度。爲什麼OmniThreadLibrary的ForEach阻止主線程?

當調用下面的過程時,應用程序GUI將停止處理任何輸入,直到所有線程都完成爲止。我的理解是,即使線程正在運行,使用.NoWait也應允許該過程退出。

procedure Test(input: TStringList; output: TList<TMaintFore>); 
var 
    outQueue: IOmniBlockingCollection; 
    transaction: TOmniValue; 
begin 
    outQueue := TOmniBlockingCollection.Create; 
    Parallel.ForEach(0, input.Count - 1) 
    .NoWait 
    .Into(outQueue) 
    .Execute(
     procedure(const value: integer; var result: TOmniValue) 
     begin 
     result := TMaintFore.Create(input[value]); 
     end 
    ); 
end; 

我對ForEach循環的理解不正確,提示我應該使用其他方法來實現後臺處理?任何關於正確使用OmniThreadLibrary的建議,我都讚賞。

回答

10

您必須將從Parallel.ForEach返回的接口存儲在全局(表單等)變量中,並且只有在ForEach完成執行時纔將其銷燬。

在您的示例中,ForEach的結果存儲在臨時變量中,該變量在測試過程退出時被銷燬。 ForEach析構函數等待所有任務完成並阻止您的程序。

在任務完成時銷燬foreach接口的最安全(但不言而喻)的方式是使用OnStop方法,並從中將命令排隊到主線程。

var 
    loop: IOmniParallelLoop<integer>; 

loop := Parallel.ForEach(1, N).NoWait; 
loop.OnStop(
    procedure (const task: IOmniTask) 
    begin 
    task.Invoke(
     procedure 
     begin 
     // do anything 
     loop := nil; 
     end); 
    end); 
loop.Execute(
    procedure (const value: integer) 
    begin 
    ... 
    end); 

這記錄在the wiki

+1

您可以安排在任務完成時收到通知嗎? –

+0

回答上面。 – gabr

+1

謝謝。這對我自己的教育來說更是一個問題,因爲我看到你在我的支持和呼喚! ;-)但我猜想提問者可能會好奇同樣的事情。 –