簡體   English   中英

將消息傳遞給參與者時,如何解決“對象引用”問題?

[英]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);
        }
    }
}

並不是說這是一個好的解決方案,但是您可以限制TICloneable並在獲得對象時對其進行克隆。 在某種程度上,這與您描述的“序列化為JSON”方法在思想上等效。 不用說,這將是笨拙且緩慢的。

確實,您應該只記得保持消息不變。 C#不是一種可以很好地為您實施的語言。

我認為您在這里沒有問題-如果_messageChannel上發生任何類型的序列化,則您的被調用者將不會獲得對原始對象的引用,而是將獲得原始對象的副本。

如果在調用完成后獲得返回的“引用”是很重要的,那么您可能想考慮使用一個標識符而不是僅僅依靠類引用,然后使用該標識符來定位原始對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM