2012-08-01 29 views
2

所有,我有一個名爲TaskSpin通用的方法,這個方法我推出一個Task與ascociated continutation隊列Mutithreaded方法執行

public TaskSpin(Func asyncMethod, object[] methodParameters) 
{ 
    ... 
    asyncTask = Task.Factory.StartNew<bool>(() => 
     asyncMethod(uiScheduler, methodParameters)); 

    asyncTask.ContinueWith(task => 
    { 
     // Finish the processing update UI etc. 
    } 
    ... 
} 

的問題是,現在我想用TaskSpin多種方法來運行,但我需要限制這些方法一次運行一次。因此,在一些DataGridView的foreach行我想要做這樣的事情

foreach (DataGridViewRow row in this.DataGridViewUrg.Rows) 
    TaskSpin(Run(DrgDataRowInfo(row.Index))); 

然而,在上述TaskSpin方法將立即退出引起TaskSpin分拆下一個方法上的另一個線程。這是不好的,因爲Run方法寫入一組通用文件。排列這些工作的最佳方式是什麼?

謝謝你的時間。

+0

有沒有理由不能通過在調度程序中拋出這些操作來使用內置隊列? – 2012-08-01 11:36:40

+0

不是我所知道的,但我不熟悉這樣做......感謝您的時間。 – MoonKnight 2012-08-01 11:43:42

回答

1

您可以實現自己的任務隊列,並在每個任務完成後繼續處理隊列,直到它爲空,例如

using TaskPair = KeyValuePair<Func, object[]>; 
... 

private Queue<TaskPair> taskQueue; 
... 

// generate the queue of tasks 
this.taskQueue = new Queue<TaskPair>(this.DataGridViewUrg.Rows); 
foreach (DataGridViewRow row in this.DataGridViewUrg.Rows) 
{ 
    var task = new TaskPair(Run(DrgDataRowInfo(row.Index)), /* params */); 
    this.taskQueue.Enqueue(task); 
} 
// initiate queue processing 
ProcessNextTask(); 

.... 
private void ProcessNextTask() 
{ 
    try 
    { 
     var item = this.taskQueue.Dequeue(); 
     TaskSpin(item.Key, item.Value); 
    } 
    catch(InvalidOperationException) 
    { 
     // queue is empty 
    } 
} 

.... 
// Execute task and process next in queue (if applicable) 
public TaskSpin(Func asyncMethod, object[] methodParameters)   
{    
    ...   
    asyncTask = Task.Factory.StartNew<bool>(() =>    
     asyncMethod(uiScheduler, methodParameters));   

    asyncTask.ContinueWith(task =>   
    {   
     // Finish the processing update UI etc. 
     ProcessNextTask();   
    } 
    ...     
} 
+0

是的,我很喜歡這個。乾杯。我打算使用'ConncurrentCollection'('BlockinCollction ')你能評論這種方法嗎?謝謝你的時間。 – MoonKnight 2012-08-01 11:46:54

+0

Downvoter care to comment? – James 2012-08-01 11:47:06

+0

下調這是荒謬的。事實。 – MoonKnight 2012-08-01 11:48:11

0

您應該考慮通過在繼續之前鎖定運行所需的對象來實現同步。你會喜歡以下內容:

// locking object for write synchronization 
object syncObj; 

... 

public TaskSpin(Func asyncMethod, object[] methodParameters) 
{ 
    ... 
    asyncTask = Task.Factory.StartNew<bool>(() => 
     asyncMethod(uiScheduler, methodParameters)); 

    asyncTask.ContinueWith(task => 
    { 
     lock(syncObj) 
     { 
      // Finish the processing update UI etc. 
     } 
    } 
    ... 
} 

public void Run() 
{ 
    lock(syncObj) 
    { 
     // write results to common file 
    } 
} 

雖然,我很確定這不會保證任務按順序完成。這聽起來像對你來說可能很重要,所以我的建議可能不完全是你想要的。

+0

如果每個任務都按順序處理,那麼就不需要鎖定。 – James 2012-08-01 11:38:47

+0

是的,但延續鏈方法基本上是以串行方式執行工作,並且否定了使用任務並行庫的好處。 – 2012-08-01 11:49:45

+0

我試圖提出的一點是,作爲Run方法重入問題解決方案的工作本身的強制序列化並不是完成工作的最有效方式。 – 2012-08-01 11:55:41

1

您可以使用延續鏈實現任務的「隊列」。這很容易閱讀和理解,並將按預期工作。此外,「排隊」邏輯現在包含在TaskSpin中。

private Task lastTask; 

public void TaskSpin(Func asyncMethod, object[] methodParameters) 
{ 
    ... 
    if(lastTask == null) 
     asyncTask = Task.Factory.StartNew<bool>(() => 
      asyncMethod(uiScheduler, methodParameters)); 
    else 
     asyncTask = lastTask.ContinueWith(t => 
      asyncMethod(uiScheduler, methodParameters)); 

    lastTask = asyncTask; 

    asyncTask.ContinueWith(task => 
    { 
     // Finish the processing update UI etc. 
    } 
    ... 
} 

這將確保每個新任務只在上一個任務完成後纔會運行。

編輯:如果你想被列入順序隊列的UI任務,一個簡單的變化:

private Task lastTask; 

public void TaskSpin(Func asyncMethod, object[] methodParameters) 
{ 
    ... 
    if(lastTask == null) 
     asyncTask = Task.Factory.StartNew<bool>(() => 
      asyncMethod(uiScheduler, methodParameters)); 
    else 
     asyncTask = lastTask.ContinueWith(t => 
      asyncMethod(uiScheduler, methodParameters)); 

    lastTask = asyncTask.ContinueWith(task => 
    { 
     // Finish the processing update UI etc. 
    } 
    ... 
} 
0

如果你的目標是連載更新到用戶界面,這有反正因爲發生UI只能從GUI線程更新。幸運的是,這樣做的機制已經內置。

我注意到你使用的是winforms。鑑於此,我建議使用一種機制,如SafeInvoke。這將排隊在GUI線程上執行的代碼。

+0

更新uI不是問題 - 我的TaskSpin方法使用'TaskScheduler.FromCurrentSynchronizationContext()'來處理這個問題。謝謝... – MoonKnight 2012-08-01 12:03:10