BinaryFormatter是否对线程安全进行序列化和反序列化?

时间:2009-09-21 09:43:39

标签: c# multithreading serialization thread-safety

引用this回答问题。

可以改写为:

    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)一个新的BinaryFormatter?

这段代码路径非常频繁,因为它涉及我们的缓存层,我希望尽可能轻量化。

感谢。

2 个答案:

答案 0 :(得分:10)

根据MSDN

  

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

因此,您需要同步对Serialize / Deserialize方法的访问。

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


更新:

我相信MSDN,因为即使在某些情况下我们可以验证实例成员可能是线程安全的,但这并不意味着对于下一个Service Pack / update / framework版本,这将继续是这种情况。

在BinaryFormatter构造函数中使用Reflector查找:

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)应该非常快。恕我直言,大部分时间都花在序列化/反序列化方法上。

答案 1 :(得分:7)

您可以使用[ThreadStatic]属性并初始化value是否为null。假设您重用线程,这将有效。

[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并查看二进制格式化程序的实现。阅读完代码后,您应该能够确定是否可以安全地进行交叉线程使用;但是,达林是正确的,因为它可能在未来的版本中破裂。