不久前,我把一个简单的类
Actor
这是我对
Actor Model
. 从那时起我就成功地使用了它(
减去一些恼人的解决方法,因为缺乏歧视性的工会类型。
)我只剩下一个问题,我不确定如何解决,而不会使课堂变得笨拙和缓慢。
当某人定义一条消息时,他们当然有权包含对调用方自己可以操作的对象的引用。即使知道我将几乎是唯一一个使用这门课的人,这仍然困扰着我。
一个很好的例子就是
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);
}
}
}