2011-02-07 95 views
3

我即將開始一個創建作業調度程序的C#.NET 4.0項目。使用多線程優先的Job Scheduler

  1. 該作業沒有到期日,可能長期運行,直到幾天。
  2. 該工作有3個優先級:空閒,正常,關鍵;從最低到最高。
  3. 新工作不斷創建。
  4. 即使舊作業已經創建很長時間,具有較高優先級的較新作業應該優先於較低優先級作業。
  5. 每個作業將由單個長時間運行的線程處理。
  6. 工作是可重入的。工作狀態被持久保存到數據庫中,因此可以隨時暫停作業或終止作業線程。

我的計劃是使用信號量,並將併發條目數設置爲系統核心數。將爲隊列中的每個作業創建一個新線程,並且所有線程在開始時將被信號量阻塞。

我的問題是保證高優先級的線程在信號量調用release()方法時首先進入信號量。可行?

我的第二個問題是當高優先級的作業線程到來時讓信號內部有一個線程退出,並讓退出的作業線程返回到線程隊列以等待信號量。可行?

對於這兩個問題,信號量是正確的方法嗎?如果不是,你建議什麼?

+0

爲什麼不使用Quartz.Net? – 2011-02-07 18:24:19

+1

那麼,我的調度方案純粹是基於優先級的,而某些工作需要根據新的工作到達來停止。石英網可以幫我嗎? – nobody 2011-02-07 18:29:10

+1

不確定停止正在運行的作業,但Quartz.Net確實具有基於優先級的處理。 – 2011-02-07 18:32:23

回答

4

那麼,我會更傾向於像下面這樣的東西......你想

首先,啓動所有的線程:

for(int i=0; i < Environment.ProcessorCount; i++) 
{ 
    Thread t = new Thread(RunWork); 
    // setup thread 
    t.Start(); 
    threads.Add(t); 
} 

您將需要一個接口來描述一個任務

interface ITask { 
    PrioirtyType Prioirty { get; } 
    bool Complete { get; } 
    void PerformOneUnitOfWork(); 
} 

然後創建一個隊列管理對象的優先級。這顯然得到,因爲它可能需要與數據庫等同步更復雜......

class MyQueue<TJob> where TJob : ITask 
{ 
    Queue<TJob> high, med, low; 
    bool GetNextJob(ref TJob work) 
    { 
     if(work.Priority == PriorityType.High && !work.Complete) 
      return true; 
     lock(this) 
     { 
      if(high.Count > 0) 
      { 
       Enqueue(work);//requeue to pick back up later 
       work = high.Dequeue(); 
       return true; 
      } 
      if(work.Priority == PriorityType.Med && !work.Complete) 
       return true; 
      if(med.Count > 0) 
      { 
       Enqueue(work);//requeue to pick back up later 
       work = med.Dequeue(); 
       return true; 
      } 
      if(!work.Complete) 
       return true; 
      if(low.Count > 0) 
      { 
       work = low.Dequeue(); 
       return true; 
      } 
      work = null; 
      return false; 
     } 

    void Enqueue(TJob work) 
    { 
     if(work.Complete) return; 
     lock(this) 
     { 
      else if(work.Priority == PriorityType.High) high.Enqueue(work); 
      else if(work.Priority == PriorityType.Med) med.Enqueue(work); 
      else low.Enqueue(work); 
     } 
    } 
} 

,最後創建工作線程類似如下:

public void RunWork() 
{ 
    ITask job; 
    while(!_shutdown.WaitOne(0)) 
    { 
     if(queue.GetNextJob(ref job)) 
      job.PerformOneUnitOfWork(); 
     else 
      WaitHandle.WaitAny(new WaitHandle[] { _shutdown, queue.WorkReadyHandle }); 
    } 
} 
3

對於這兩個問題,信號量是否正確?如果不是,你建議什麼?

這真的取決於。通常,每個線程最好有多個作業,因爲許多(尤其是長時間運行的)工作項將花費其他時間等待CPU以外的其他工作。例如,如果您從WCF服務或其他相關問題中完成工作,則可能會花費大量時間來阻止和閒置。

在這種情況下,根據需要讓工作進度安排可能會更好。在這種情況下使用ThreadPool可能會更好。

但是,如果作業都是高CPU,那麼你的方法可能是可取的。可以使用優先級隊列來跟蹤調度優先級,並確定要運行的作業。

這就是說,我可能不會使用這個信號量。雖然它可以工作,但單個計數器(通過Interlocked.Increment/Decrement管理)和ManualResetEvent也可以工作,並且重量更輕。