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

Kie*_*ton 14 c# serialization multithreading 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);
            stream.Position = 0;
            return (T)formatter.Deserialize(stream);
        }
    }
Run Code Online (Sandbox Code Playgroud)

那么为每次调用避免构造(和GC)一个新的BinaryFormatter?

这个代码路径非常频繁,因为它涉及我们的缓存层,我想尽可能轻量级.

谢谢.

Dar*_*rov 10

根据MSDN:

此类型的任何公共静态(在Visual Basic中为Shared)成员都是线程安全的.任何实例成员都不保证是线程安全的.

因此,您需要同步对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);
}
Run Code Online (Sandbox Code Playgroud)

和StreamingContext构造函数:

public StreamingContext(StreamingContextStates state, object additional)
{
    this.m_state = state;
    this.m_additionalContext = additional;
}
Run Code Online (Sandbox Code Playgroud)

坦率地说,分配6个属性(大多数属性enums)应该非常快.恕我直言,大部分时间都将花在序列化/反序列化方法上.

  • 是的,这就是当前的热门路径(我们已经测量过)。为每个请求实例化格式化并不是世界末日,但我想知道是否有人知道它是否进行内部缓存等。我知道 MSDN 上的通知,但正如您可能知道的那样,它说对于很多实际上实际上是实例线程安全的类:) (2认同)

csh*_*net 8

您可以使用[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);
            }
    }
Run Code Online (Sandbox Code Playgroud)

当然,另一种选择是使用Red Gate的Relfector.Net并查看二进制格式化程序的实现.阅读完代码后,您应该能够确定是否可以安全地进行交叉线程使用; 但是,达林是正确的,因为它可能在未来的版本中打破.