2009-09-21 6 views
12

Riferimento a this risposta a una domanda.Are BinaryFormatter Serialize e Deserialize thread safe?

questo può essere riscritto come:

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); 
     } 
    } 

evitando così la costruzione (e GC'ing) un nuovo BinaryFormatter per ogni chiamata?

Questo percorso di codice viene colpito molto frequentemente poiché coinvolge il nostro livello di memorizzazione nella cache e vorrei renderlo il più leggero possibile.

Grazie.

+1

Un argomento classico per immutabile;) –

risposta

9

Secondo MSDN:

statici pubblici (in Visual Basic) di questo tipo sono thread sicuri. Qualsiasi membro di istanza non è garantito come thread-safe.

Quindi è necessario sincronizzare l'accesso ai metodi di serializzazione/deserializzazione.

Avete identificato particolari problemi di prestazioni creando ogni volta un'istanza di serializzatore locale?


UPDATE:

mi fiderei MSDN perché anche se in alcuni casi si può verificare che i membri di istanza potrebbe essere thread-safe questo non significa che con il servizio successivo pacchetto/aggiornamento/versione framework questo continuerà ad essere il caso.

Guardando con riflettore al costruttore BinaryFormatter:

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

E StreamingContext costruttore:

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

Francamente l'assegnazione di 6 immobili (la maggior parte dei quali sono enums) dovrebbe essere veloce come il fulmine. IMHO la maggior parte del tempo sarebbe speso in metodi Serialize/Deserialize.

+0

Sì, che è attualmente il percorso hot (che abbiamo misurato). Non è la fine del mondo ad instanciare un formato per ogni richiesta, ma mi chiedevo se qualcuno sapeva se faceva il caching interno, ecc. Ero a conoscenza della notifica su MSDN, ma come probabilmente sapete, si dice che per un sacco di classi che in realtà sono thread di istanze sicure in realtà :) –

6

È possibile utilizzare l'attributo [ThreadStatic] e inizializzare se il valore è nullo. Questo funzionerà assumendo il tuo riutilizzo di thread.

[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); 
      } 
    } 

Naturalmente, l'altra opzione è quella di utilizzare Relfector.Net da Red Gate e rivedere l'attuazione del formattatore binario. Dopo aver letto il codice dovresti essere in grado di decidere se è sicuro per l'uso con thread incrociati; tuttavia, Darin ha ragione in quanto potrebbe irrompere in una versione futura.