none
Performance issue in .NET remoting

    General discussion

  • I can't understand why this strange behavior when I call the method remotely is expensive.

    I have observed a performance issue when my object method called remotely compared to when it's called within the same process. To confess, I don't have good understanding of .NET remoting technology. Yes I have read few articles, but I haven't understood how to resolve this specific problem.

    I had supportive data from ants performance profiler which clearly shows call to DisconnectFromPublisher()-> UnsubscribeAll(); is expensive.

    I have modified my code to simplify the problem. The skeleton is as follows. Give me some pointers why the method is expensive when it's invoked remotely.



    /// <summary>
    /// A data object that holds callback information.
    /// </summary>
    public class CallbackDelegate
    {
        /// <summary>
        /// The delegate that should be invoked to perform the callback.
        /// </summary>
        public SampleDelegate SampleDelegate;

        /// <summary>
        /// The client control that has the callback method.
        /// This value can be null.
        /// </summary>
        public Control ClientControl;

        /// <summary>
        /// a unique key is used to identify each callback info
        /// </summary>
        public Guid CallbackDelegateKey;
    }

    /// <summary>
    /// A helper class that allows clients to receive notification messages
    /// by subscribing to topics.
    /// </summary>
    public class Subscriber : MarshalByRefObject
    {
        #if DEBUG
        // Allows exceptions to be injected during unit testing of debug builds.
        private string _testCase = null;
        #endif

        /// <summary>
        /// The publisher to which this subscriber is connected.
        /// </summary>
        public Publisher Publisher
        {
            get { return _publisher; }
        }
        private Publisher _publisher;


        /// <summary>
        /// Notification Dispatcher
        /// </summary>
        private Dispatcher _Dispatcher = new Dispatcher();

        private Dictionary<string, List<CallbackDelegate>> _clientCallbacks = new Dictionary<string, List<CallbackDelegate>>();

        /// <summary>
        /// sync object for client callbacks list
        /// </summary>
        private object _syncObj = new object();
        /// <summary>
        /// Constructor for a notification subscriber.
        /// </summary>
        public Subscriber()
        {
            _Dispatcher.Notify += new EventHandler<NotificationEventArgs>                                   (_Dispatcher_Notify);
        }

        public void Unsubscribe(string topicName)
        {
            // Check the method parameter.
            if (topicName == null)
            {
                throw new ArgumentNullException();
            }
            try
            {
                lock (_syncObj)
                {
                    // Remove the client callback (indexed by topic name).
                    _clientCallbacks.Remove(topicName);
                }

            }
            catch (Exception)
            {
                throw;
            }
        }


        /// <summary>
        /// Unsubscribes from all topics that this object has susbcribed to.
        /// </summary>
        /// <exception cref="PublisherAccessException">An error occurred while         unsubscribing from a topic.</exception>
        public void UnsubscribeAll()
        {
            lock (_syncObj)
            {
                // Access the topic names before modifying the list (with Unsubscribe).
                Queue<string> topics = new Queue<string>();
                foreach (string name in _clientCallbacks.Keys)
                {
                    topics.Enqueue(name);
                }

                //For each topic name...
                while (topics.Count > 0)
                {
                    string topicName = topics.Dequeue();

                    // Unsubscribe the topic.
                    Unsubscribe(topicName);
                }
            }
        }

        /// <summary>
        /// Disconnects from the publisher.
        /// This subscriber will no longer subscribe to any topics.
        /// </summary>
        /// <exception cref="PublisherAccessException">An error occurred while unsubscribing from a topic.</exception>
        public void DisconnectFromPublisher()
        {
            try
            {
                _Dispatcher.Stop();
                // Unsubscribe from all topic.
                UnsubscribeAll();
            }
            catch (PublisherAccessException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new PublisherAccessException("An error occurred while disconnecting from the notification publisher.", ex);
            }
            finally
            {
                // Do not keep a reference to the publisher.
                _publisher = null;
                lock (_syncObj)
                {
                    _clientCallbacks.Clear();
                }
            }
        }
    }
    Saturday, October 18, 2014 4:52 AM

All replies

  • Remoting?

    That's the old way of doing stuff.

    If you're concerned about efficiency/reliability/maintenance then I would recommend refactoring to something else - such as WCF.

    Saturday, October 18, 2014 8:52 AM
  • its a legacy system and software has many dependent clients. I can't change the technology/software.
    Saturday, October 18, 2014 10:44 AM
  • I haven't used remoting in a long time.

    One of the problems was that it was inherently inefficient.

    So what you're seeing could well just be "normal" using remoting.

    Saturday, October 18, 2014 4:40 PM