Usando Singleton vs Single Call in .NET Remoting?
-
07-07-2019 - |
Domanda
Fino a questo punto tutto il codice di remoting .NET con cui ho scritto o lavorato è stato esposto come SingleCall.
Mi sono imbattuto in un componente remoto .NET ospitato in un servizio Windows esposto come Singleton.
Questo oggetto ha il potenziale per essere chiamato da più di un client contemporaneamente e non ha blocchi o altre disposizioni per proteggere il suo stato interno.
Se capisco Singleton correttamente, questo ha il potenziale per grossi problemi corretti?
Soluzione
Non c'è più potenziale di un componente SingleCall. Entrambi avranno problemi se tentano di accedere a una posizione di memoria condivisa in modo non sicuro.
La differenza tra SingleCall e Singleton è che, per SingleCall, ogni richiesta in arrivo otterrà una nuova istanza del tipo definito creata per gestire quella chiamata. Ogni istanza avrà il proprio spazio di memoria e variabili di istanza, ma potrà comunque condividere variabili statiche e globali, risorse esterne, file, connessioni di rete, ecc. Se la classe SingleCall è codificata per accedere a qualsiasi stato di memoria condivisa in modo thread-safe , allora avrai problemi.
Un Singleton, d'altra parte, ottiene solo un'istanza creata per TUTTE le richieste in arrivo, quindi per definizione, ogni variabile di istanza in uso all'interno di quel singleton è, di fatto, condivisa tra tutte le richieste in arrivo. Un buon esempio potrebbe essere un editore di messaggi, a cui tutto il codice nel server deve accedere per inviare messaggi a uno o più client sottoscritti ....
Per rispondere ai commenti di @Cocowalla, assicurati di fare in modo che tu ignori il metodo
MarshalByRefObject.InitializeLifetimeService()
come mostrato, o il tuo singleton si spegnerà inaspettatamente se nessuno lo chiama per un po '...
public class MessageManager : MarshalByRefObject
{
#region Singleton / MarshalByRefObject code
private static MessageManager mgr =
new MessageManager(); // creates singleton
static MessageManager() { }
private MessageManager() { }
public static MessageManager Instance { get { return mgr; } }
public override object InitializeLifetimeService() { return (null); }
#endregion Singlelton code
// ... other stuff ...
}
// in Remoting Host initialization code...
MessageManager mgr = MessageManager.Instance; // generates singleton;
RemotingServices.Marshal(mgr, URI);
Altri suggerimenti
Sì. Se i chiamanti modificano lo stato interno dell'oggetto e quei metodi non sono thread-safe, allora sei destinato a metterti nei guai. Quel server dovrebbe essere a chiamata singola.
Ma come sottolinea Charles, se l'oggetto server accede a risorse condivise (e quale server utile no?), anche i server a chiamata singola possono avere problemi. Tuttavia, questi problemi sono più gestibili. L'accesso a un database, ad esempio, può essere facilmente reso transazionale e quindi sicuro.
In conclusione: fare una chiamata singola è un modo semplice ed efficace per sbarazzarsi della metà dei tuoi problemi. Attenersi ad esso.