2013-03-04 77 views
3

我的圖像庫中有以下代碼,它利用處理器列表動態地處理由HttpModule捕獲的圖像。線程安全無鎖

目前只創建每個處理器的一個實例,以便減少內存開銷,並且每個處理器都有可寫屬性,這些屬性有助於確定處理每個匹配查詢字符串參數的順序並存儲解析值以處理。

正如你所看到的,我目前正在將lock語句中的方法功能包裝起來,以防止來自HttpModule的不同線程覆蓋處理器屬性,儘管我知道這可能是瓶頸。我想知道的是:有沒有設計模式或方法可以讓我的處理器在沒有鎖的情況下進行線程安全?

public static ImageFactory AutoProcess(this ImageFactory factory) 
{ 
    if (factory.ShouldProcess) 
    { 
     // TODO: This is going to be a bottleneck for speed. Find a faster way. 
     lock (SyncLock) 
     { 
      // Get a list of all graphics processors that 
      // have parsed and matched the querystring. 
      List<IGraphicsProcessor> list = 
       ImageProcessorConfig.Instance.GraphicsProcessors 
       .Where(x => x.MatchRegexIndex(factory.QueryString) != int.MaxValue) 
       .OrderBy(y => y.SortOrder) 
       .ToList(); 

      // Loop through and process the image. 
      foreach (IGraphicsProcessor graphicsProcessor in list) 
      { 
       factory.Image = graphicsProcessor.ProcessImage(factory); 
      } 
     } 
    } 

    return factory; 

} 
+5

您是否有證據證明這是一個瓶頸?不要浪費寶貴的時間來解決你沒有的問題的危險和棘手的解決方案。如果它是一個瓶頸,那麼解決方案的第一次嘗試應該是*儘可能多地在鎖外部進行工作*而不是試圖*消除鎖*。非常規鎖定非常快*;我們正在談論納秒。競爭鎖定價格昂貴;您可以通過在鎖內不做太多工作來消除爭用。 – 2013-03-04 23:45:17

+0

說實話,我沒有。我會想,雖然它會。我已經儘可能地優化了我的ImageFactory類,以便它不需要圍繞「Bitmap」進行任何鎖定,並且考慮到我可能有可能處理數千個圖像,因此沒有儘可能優化該流程似乎是浪費。 我其實並不知道他們那麼快。 – 2013-03-04 23:49:47

回答

2

生產者消費者隊列可能是你感興趣的。通常,您的HttpModule會接收事件(生產者)並將它們排隊到一個或多個IGraphicsProcessor(消費者)實例。

這是規範的,最簡單可行的生產者/消費者隊列實現:http://www.albahari.com/threading/part4.aspx#_Wait_Pulse_Producer_Consumer_Queue

如果你是在消除鎖定的意圖,你應該使用無鎖隊列實現生產者/消費者隊列,如System.Collections.Concurrent.ConcurrentQueue<T>實驗性功能。 NET 4.0。

+0

剛纔我會看看這個。我實際上已經在另一個標籤中打開了第一頁。 – 2013-03-04 23:53:32

2

要麼因爲沒有多個處理器而需要保持內存壓力(然後您需要至少允許給定的處理器完成當前工作),否則您需要完全併發。

除非有明確的理由,否則我會允許每個圖像處理器的多個實例。確保處理器儘早釋放它正在處理的數據的引用,以便GC以最佳方式運行。這具有簡單的優點,並且具有CPU核心的優勢。

如果有明確的理由只允許每個處理器的一個實例,則可以通過避免當前鎖定的情況來改進代碼,直到處理器完成所有處理器的工作。相反,一旦當前項目完成,您可以有一種機制來請求每個處理器需要處理下一個項目。 @安東尼的建議使用生產者/消費者模式似乎是一個堅實的解決方案。請記住,採用這種方法,您仍然會阻礙每個單獨過濾器的吞吐量,並且您可能無法優化所有CPU內核。

+0

僅有一個實例背後的其他主要原因之一是可擴展性。我正在加載並在應用程序啓動時創建一個'IGraphicsProcessor'接口的所有實例。這個想法是,圖書館可以通過拖放dll的方式進行擴展。 – 2013-03-04 23:56:50

+0

如果實例化實例的開銷很大,則可以使用對象池來管理預初始化對象的N個實例。如果實例化一個實例並不昂貴,那麼沒有理由預先創建它們。你有具體的測量(或對未來插件的期望)初始化開銷會很高嗎? – 2013-03-05 00:08:01

+0

嗯,沒有。任何未來的實現都應該是輕量級的。然而,目前我必須創建並實例化所有這些查詢字符串,每次我調用該方法時,都要使用每個正則表達式來解析查詢字符串。 – 2013-03-05 00:24:03