Il ya quelque temps, j'ai mis en place une classe simple nommée Actor
qui était ma mise en œuvre du Actor Model. Depuis lors, je l'ai utilisé avec beaucoup de succès (Moins certaines solutions de contournement ennuyeuses pour l'absence d'un type d'union discriminé.)). Je suis à gauche avec un problème que je ne sais pas comment résoudre sans rendre la classe maladroite et lente.Comment puis-je contourner mon problème de "référence d'objet" lors de la transmission de messages à un acteur?
Lorsqu'une personne définit un message, elle a bien entendu le droit d'inclure une référence à un objet que l'appelant peut lui-même manipuler. Même avec la certitude que je serai la seule personne à utiliser cette classe, cela me dérange toujours.
Un bon exemple d'un moyen de contourner cela est avec Web Workers tel que mis en œuvre dans Firefox. Lors du passage d'un objet à un worker, il est sérialisé en JSON.
Des idées?
public abstract class Actor<T, U> : IDisposable
{
private const int AsyncChannelPoolSize = 20;
private volatile bool _disposed;
private readonly Thread _actorThread;
private readonly AsyncReplyChannel<T, U> _messageChannel;
private readonly Lazy<ObjectPool<AsyncChannel<U>>> _asyncChannelPool;
public event EventHandler<ExceptionEventArgs> Exception;
protected Actor()
{
_messageChannel = new AsyncReplyChannel<T, U>();
_asyncChannelPool = new Lazy<ObjectPool<AsyncChannel<U>>>(() => new ObjectPool<AsyncChannel<U>>(AsyncChannelPoolSize));
_actorThread = new Thread(ProcessMessages);
_actorThread.IsBackground = true;
_actorThread.Start();
}
public U PostWithReply(T value)
{
ThrowIfDisposed();
var replyChannel = default(AsyncChannel<U>);
var replyPackage = default(AsyncReplyPackage<T, U>);
var replyMessage = default(U);
try
{
replyChannel = _asyncChannelPool.Value.Get();
replyPackage = new AsyncReplyPackage<T, U>(value, replyChannel);
_messageChannel.Send(replyPackage);
replyMessage = replyChannel.Receive();
}
finally
{
_asyncChannelPool.Value.Put(replyChannel);
}
return replyMessage;
}
public void PostWithAsyncReply(T value, IAsyncChannel<U> replyChannel)
{
ThrowIfDisposed();
_messageChannel.Send(new AsyncReplyPackage<T, U>(value, replyChannel));
}
public void Dispose()
{
Dispose(true);
}
protected abstract void ProcessMessage(AsyncReplyPackage<T, U> package);
protected virtual void OnException(Exception ex)
{
var exceptionEvent = Exception;
if (exceptionEvent != null)
{
exceptionEvent(this, new ExceptionEventArgs(ex));
}
}
protected virtual void Dispose(bool disposing)
{
_disposed = true;
_messageChannel.Dispose();
if (_asyncChannelPool.IsValueCreated)
{
_asyncChannelPool.Value.Dispose();
}
}
private void ProcessMessages()
{
var package = default(AsyncReplyPackage<T, U>);
while (_messageChannel.TryReceive(out package) && !_disposed)
{
try
{
ProcessMessage(package);
}
catch (Exception ex)
{
OnException(ex);
}
}
}
private void ThrowIfDisposed()
{
if (_disposed)
{
throw new ObjectDisposedException(GetType().FullName);
}
}
}
J'ai tendance à faire tout ce que je peux immuable. Je pense que c'est plus une question de type de pureté théorique si cela a du sens. J'ai l'impression que vous avez dit que C# n'a vraiment aucune solution à ce problème qui fonctionnerait très bien. – ChaosPandion
Je vais accepter cette réponse pour être le vérificateur des mauvaises nouvelles. – ChaosPandion