2009-09-21 113 views
12

參考this回答一個問題。BinaryFormatter序列化和反序列化線程安全嗎?

是否可以將其改寫爲:

private static BinaryFormatter formatter = new BinaryFormatter(); 

    public static T DeepClone<T>(this T a) 
    { 
     using(MemoryStream stream = new MemoryStream()) 
     { 
      formatter.Serialize(stream, a); 
      stream.Position = 0; 
      return (T)formatter.Deserialize(stream); 
     } 
    } 

所以避免了構建(及GC'ing)爲每個調用一個新的BinaryFormatter?

此代碼路徑非常頻繁地被擊中,因爲它涉及到我們的緩存層,我希望儘可能輕量化。

謝謝。

+1

不可變的經典論據;) – 2009-09-21 13:36:48

回答

9

根據MSDN

任何公共靜態此類型的成員(在Visual Basic中的Shared)是線程安全的 。任何實例成員不是 保證是線程安全的。

所以你需要同步對Serialize/Deserialize方法的訪問。

您是否通過每次創建本地串行器實例來識別出特定的性能問題?


UPDATE:

我會信任MSDN因爲即使在某些情況下,我們可以驗證實例成員可能是線程安全的,這並不意味着下一個服務包/更新/框架版本將繼續如此。

與BinaryFormatter的構造反射展望:

public BinaryFormatter() 
{ 
    this.m_typeFormat = FormatterTypeStyle.TypesAlways; 
    this.m_securityLevel = TypeFilterLevel.Full; 
    this.m_surrogates = null; 
    this.m_context = new StreamingContext(StreamingContextStates.All); 
} 

而構造的StreamingContext:

public StreamingContext(StreamingContextStates state, object additional) 
{ 
    this.m_state = state; 
    this.m_additionalContext = additional; 
} 

坦率地分配6處房產(其中大部分是enums)應該是快如閃電。恕我直言,大部分時間將用於Serialize/Deserialize方法。

+0

是的,這是目前熱門的路徑(我們測量過)。它並不是世界末日爲每個請求提供格式化的信息,但是我想知道是否有人知道它是否執行了內部緩存等。我知道MSDN上的通知,但正如您可能知道的那樣,它說很多實際上實例線程安全的類:) – 2009-09-21 09:52:06

6

如果value爲null,您可以使用[ThreadStatic]屬性並進行初始化。這將工作假設你重用線程。

[ThreadStatic] 
private static BinaryFormatter formatter = null; 

public static T DeepClone<T>(this T a) 
    { 
      if(formatter == null) formatter = new BinaryFormatter(); 
      using(MemoryStream stream = new MemoryStream()) 
      { 
        formatter.Serialize(stream, a); 
        stream.Position = 0; 
        return (T)formatter.Deserialize(stream); 
      } 
    } 

當然,另一種選擇是使用Red Gate的Relfector.Net並查看二進制格式化程序的實現。在閱讀代碼後,您應該能夠決定是否安全使用交叉線程;然而,達林是正確的,因爲它可能會在未來的版本中打破。