2012-11-21 169 views
3

我有一個需要實時更新的數據集列表。我想每次處理100個以上的10個,然後一旦完成,就抓住下一個最老的線。基本上保持這個循環持續無限的時間。我對線程的世界很陌生,並且一直在AsyncTask中探索。有沒有人可以指點我的例子?我GOOGLE了很多,但無法找到我正在尋找的東西。與無限循環異步

回答

2

AsyncTask更適合於一次性的操作。對於正在進行的任務,您可以考慮一個工作線程。

聲明:我不主張這是做到這一點的最好辦法,但它應該給你一些想法和東西上閱讀了。

public class ThreadingSample : IDisposable 
{ 
    private Queue<SomeObject> _processingQueue = new Queue<SomeObject>(); 
    private Thread _worker; 
    private volatile bool _workerTerminateSignal = false; 
    private EventWaitHandle _waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); 

    public bool HasQueuedItem 
    { 
     get 
     { 
      lock(_processingQueue) 
      { 
       return _processingQueue.Any(); 
      } 
     } 
    } 

    public SomeObject NextQueuedItem 
    { 
     get 
     { 
      if (!HasQueuedItem) 
       return null; 

      lock(_processingQueue) 
      { 
       return _processingQueue.Dequeue(); 
      } 
     } 
    } 

    public void AddItem(SomeObject item) 
    { 
     lock(_processingQueue) 
     { 
      _processingQueue.Enqueue(item); 
     } 
     _waitHandle.Set(); 
    } 
    public ThreadingSample() 
    { 
     _worker = new Thread(ProcessQueue); 
     _worker.Start(); 
    } 

    private void ProcessQueue() 
    { 
     while(!_workerTerminateSignal) 
     { 
      if (!HasQueuedItem) 
      { 
       Console.WriteLine("No items, waiting."); 
       _waitHandle.WaitOne(); 
       Console.WriteLine("Waking up..."); 
      } 
      var item = NextQueuedItem; 
      if (item != null) // Item can be missing if woken up when the worker is being cleaned up and closed. 
       Console.WriteLine(string.Format("Worker processing item: {0}", item.Data)); 
     } 
    } 

    public void Dispose() 
    { 
     if (_worker != null) 
     { 
      _workerTerminateSignal = true; 
      _waitHandle.Set(); 
      if (!_worker.Join(TimeSpan.FromMinutes(1))) 
      { 
       Console.WriteLine("Worker busy, aborting the thread."); 
       _worker.Abort(); 
      } 
      _worker = null; 
     } 
    } 

    public class SomeObject 
    { 
     public string Data 
     { 
      get; 
      set; 
     } 
    } 
} 

測試它我使用單元測試來啓動它。您可以將單元測試擴展爲適當的測試,以確保按預期執行操作。在我的情況下,他們是一個很好的初步斷言,以突出行爲。

 [Test] 
    public void TestThreading() 
    { 
     using (var sample = new ThreadingSample()) 
     { 
      sample.AddItem(new ThreadingSample.SomeObject {Data = "First Item"}); 
      sample.AddItem(new ThreadingSample.SomeObject {Data = "Second Item"}); 
      Thread.Sleep(50); 
      sample.AddItem(new ThreadingSample.SomeObject {Data = "Third Item"}); 
     } 

    } 
從測試輸出

相關:

------測試開始:大會:NHMapping.dll ------

工人處理項目:第一個項目
工作人員處理項目:第二個項目
沒有項目,正在等待。
醒來......
沒有項目,等待着。
醒來......
工人處理項目:第三項
沒有項目,等待着。
醒來......

1通過,0失敗,0跳過,花了0.12秒(Ad hoc)。

在這裏,您可以看到工作人員要睡覺,然後醒來處理隊列中的項目。從技術上講,你可以使用一個列表,然後在從鎖中釋放它之前從列表中獲取10個項目,並在再次檢查列表之前處理這10個項目。

當類配置它釋放則循環等待片刻工作線程中止之前終止。在這裏,您可能需要檢查是否有未完成的項目,並記錄它們將不會被處理,或者將它們保存到文件中供以後處理。

編輯:我發現這個問題有雙重事件...更好的實現是使用在EventWaitHandle

private EventWaitHandle _waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); 

一個ManualReset然後處理,你處理一個項目的情況下,再次打開手柄:

   var item = NextQueuedItem; 
      if (item != null) // Item can be missing if woken up when the worker is being cleaned up and closed. 
      { 
       Console.WriteLine(string.Format("Worker processing item: {0}", item.Data)); 
       _waitHandle.Reset(); 
      } 

這將產生更好的測試結果:

------測試開始:大會:NHMapping.dll ------

工作呃處理項目:第一項
工作人員處理項目:第二項
沒有項目,正在等待。
醒來......
工人處理項目:第三項
沒有項目,等待着。
醒來......

1通過,0失敗,0跳過,花了0.13秒(Ad hoc)。

+0

第二項和第三項之間的雙重喚醒有點令人感興趣,可能是由於我用每個AddItem調用觸發了'EventWaitHandle'。 –

5

至少在.NET 4.5異步編程已經變得非常含糖,如果你知道我的意思。

下面是一組簡單的例子:

public async void DoAsync() 
{ 
     await Task.Run(() => 
     { 
     // Do task! 
     }); 
} 

public async Task<string> GetStringAsync() 
{ 
     string s = ""; 
     await Task.Run(() => 
     { 
      for(int I = 0; I < 9999999; I++) 
      { 
        s += I.ToString(); 
      } 
     } 
     return s; 
} 

有用資源

http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx