[英]How can I get around my “object reference” issue when passing messages to an actor?
不久前,我整理了一個名為Actor
的簡單類,它是Actor Model的實現 。 從那時起,我就一直使用它取得了巨大的成功( 減去了由於缺少區分的聯合體類型而引起的一些煩人的解決方法。 )。 我有一個問題,我不確定如何在不使班級笨拙和緩慢的情況下解決。
當某人定義一條消息時,他們當然有權包括對調用者自己可以操縱的對象的引用。 即使知道我將是唯一使用此課程的人,這仍然讓我感到困擾。
解決此問題的一個很好的例子是在Firefox中實現的Web Workers 。 將對象傳遞給工作程序時,它會序列化為JSON。
有任何想法嗎?
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);
}
}
}
並不是說這是一個好的解決方案,但是您可以限制T
為ICloneable
並在獲得對象時對其進行克隆。 在某種程度上,這與您描述的“序列化為JSON”方法在思想上等效。 不用說,這將是笨拙且緩慢的。
確實,您應該只記得保持消息不變。 C#不是一種可以很好地為您實施的語言。
我認為您在這里沒有問題-如果_messageChannel
上發生任何類型的序列化,則您的被調用者將不會獲得對原始對象的引用,而是將獲得原始對象的副本。
如果在調用完成后獲得返回的“引用”是很重要的,那么您可能想考慮使用一個標識符而不是僅僅依靠類引用,然后使用該標識符來定位原始對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.