2010-06-08 47 views
2

我在我的.NET 4應用程序中使用並行數據結構,並且我有一個ConcurrentQueue在我通過它處理時被添加。雖然使用ConcurrentQueue,試圖在並行循環時出隊

我想要做的事,如:

personqueue.AsParallel().WithDegreeOfParallelism(20).ForAll(i => ...);

爲我做調用數據庫保存數據,所以我限制併發線程數。

但是,我想到的是,ForAll不會出隊,而我關心的只是在做

ForAll(i => { 
    personqueue.personqueue.TryDequeue(...); 
    ... 
}); 

,因爲沒有保證,我突然離開正確的。

那麼,我怎樣才能以並行方式遍歷集合和出列。

或者,使用PLINQ來並行執行此處理會更好嗎?

回答

4

那麼我不是100%確定你試圖在這裏存檔。你是否試圖將所有物品出列,直到沒有剩下物品?或者只是一次將很多物品出列?

第一個可能的意外行爲啓動與此聲明:

theQueue.AsParallel() 

對於ConcurrentQueue,你會得到一個「Snapshot'-枚舉。所以當你迭代一個併發堆棧時,你只能遍歷快照,不能訪問「實時」隊列。

總體而言,我認爲迭代迭代過程中改變的內容並不是一個好主意。

因此,另一種解決方案是這樣的:

 // this way it's more clear, that we only deque for theQueue.Count items 
     // However after this, the queue is probably not empty 
     // or maybe the queue is also empty earlier 
     Parallel.For(0, theQueue.Count, 
        new ParallelOptions() {MaxDegreeOfParallelism = 20}, 
        () => { 
         theQueue.TryDequeue(); //and stuff 
        }); 

這避免了操作的東西,而遍歷它。但是,在該語句之後,隊列仍可包含在for循環期間添加的數據。

要讓隊列空時,你可能需要多一點工作。這是一個非常難看的解決方案。雖然隊列中仍有項目,但可以創建新任務。只要可以,每個任務開始從隊列中出隊。最後,我們等待所有任務結束。爲了限制並行性,我們從未創建超過20個任務。

 // Probably a kitty died because of this ugly code ;) 
     // However, this code tries to get the queue empty in a very aggressive way 
     Action consumeFromQueue =() => 
             { 
              while (tt.TryDequeue()) 
              { 
               ; // do your stuff 
              } 
             }; 
     var allRunningTasks = new Task[MaxParallism]; 
     for(int i=0;i<MaxParallism && tt.Count>0;i++) 
     { 
      allRunningTasks[i] = Task.Factory.StartNew(consumeFromQueue); 
     } 
     Task.WaitAll(allRunningTasks); 
+0

我會嘗試中間的想法,因爲這可能工作。這是一個Web服務的一部分,它可以在很短的時間內獲得10k次更新,每次只能處理1次,但我不想通過在獲取它們時嘗試每次更新來敲擊數據庫,所以我會將它們推入一個靜態隊列,一個單身,並有一個功能來處理。我的解決方案並不完美,但我需要將數據庫作爲高優先級來保護。 – 2010-06-11 00:48:24

0

如果你的目標是在整個真正的網站高,你不必做直接的數據庫更新,你會感到非常的去爲非常保守的解決方案,而不是額外的層圖書館更好。

製作固定大小的數組(比如1000個物品或N秒的請求)和互鎖索引,以便請求只是將數據放入插槽並返回。當一個塊被填充時(保持檢查計數),再創建一個塊併產生異步委託來處理併發送給剛剛填充的塊。根據你的數據結構,委託可以將所有數據打包成逗號分隔的數組,甚至可以是一個簡單的XML(當然也可以測試其性能),並將它們發送到SQL sproc,這應該給它最好的處理記錄通過記錄 - 永遠不要拿着大鎖。如果變得沉重,你可以將你的塊分成幾個小塊。關鍵是你最大限度地減少了對SQL的請求數量,始終保持一度的分離度,甚至不必爲線程池付出代價 - 你可能根本不需要使用更多的2個異步線程。

用Parallel-s來擺弄會快很多。

+0

我希望只是在隊列被填滿時清空隊列,所以如果我在一個Web服務調用中獲得數百個項目,那麼他們會發送另一個大批量的內容,它會在內部存在內容時繼續進行。此刻我睡10秒,處理隊列,然後再睡10秒。 – 2010-08-28 00:53:02