不久前,我整理了一个名为的简单类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);
}
}
}