C# BinaryFormatter序列化和反序列化是否线程安全?

C# BinaryFormatter序列化和反序列化是否线程安全?,c#,multithreading,serialization,thread-safety,C#,Multithreading,Serialization,Thread Safety,参考问题的答案 这可以改写为: private static BinaryFormatter formatter = new BinaryFormatter(); public static T DeepClone<T>(this T a) { using(MemoryStream stream = new MemoryStream()) { formatter.Serialize(stream, a)

参考问题的答案

这可以改写为:

    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);
        }
    }
private static BinaryFormatter formatter=new BinaryFormatter();
公共静态T DeepClone(此T a)
{
使用(MemoryStream stream=new MemoryStream())
{
序列化(流,a);
流位置=0;
返回(T)格式化程序。反序列化(流);
}
}
所以避免为每个调用构造(和GC’ing)一个新的二进制格式化程序

这个代码路径经常受到攻击,因为它涉及到我们的缓存层,我希望使它尽可能轻量级

谢谢。

根据:

任何公共静态文件(在Visual Studio中共享) 基本)此类型的成员是线程 安全的。任何实例成员都不是 保证线程安全

因此,您需要同步对序列化/反序列化方法的访问

您是否通过每次创建本地序列化程序实例来确定特定的性能问题


更新:

我相信MSDN,因为即使在某些情况下,我们可以验证实例成员可能是线程安全的,但这并不意味着在下一个service pack/update/framework版本中,情况仍然如此

使用Reflector查看BinaryFormatter构造函数:

public BinaryFormatter()
{
    this.m_typeFormat = FormatterTypeStyle.TypesAlways;
    this.m_securityLevel = TypeFilterLevel.Full;
    this.m_surrogates = null;
    this.m_context = new StreamingContext(StreamingContextStates.All);
}
public StreamingContext(StreamingContextStates state, object additional)
{
    this.m_state = state;
    this.m_additionalContext = additional;
}
和StreamingContext构造函数:

public BinaryFormatter()
{
    this.m_typeFormat = FormatterTypeStyle.TypesAlways;
    this.m_securityLevel = TypeFilterLevel.Full;
    this.m_surrogates = null;
    this.m_context = new StreamingContext(StreamingContextStates.All);
}
public StreamingContext(StreamingContextStates state, object additional)
{
    this.m_state = state;
    this.m_additionalContext = additional;
}

坦率地说,分配6个属性(其中大多数是
枚举
)的速度应该非常快。大部分时间都花在序列化/反序列化方法上。

如果值为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);
            }
    }
[ThreadStatic]
私有静态二进制格式化程序格式化程序=null;
公共静态T DeepClone(此T a)
{
如果(formatter==null)formatter=new BinaryFormatter();
使用(MemoryStream stream=new MemoryStream())
{
序列化(流,a);
流位置=0;
返回(T)格式化程序。反序列化(流);
}
}

当然,另一种选择是使用RedGate中的Relfector.Net并检查二进制格式化程序的实现。在阅读代码后,您应该能够决定它是否适合跨线程使用;然而,Darin是正确的,因为它可能会在未来的版本中被打破。

是的,这是目前的热门路线(我们已经测量过)。为每个请求实例化一个格式化的类并不是世界末日,但我想知道是否有人知道它是否进行了内部缓存等。我知道MSDN上有这样的通知,但正如您可能知道的,它说,对于许多实际上是实例线程安全的类:)一个不可变的经典参数;)