簡體   English   中英

托管在另一個AppDomain中的WCF主機速度慢

[英]Slow WCF Host when hosted in another AppDomain

我有一個奇怪的問題。 如果WCF主機托管在原始AppDomain中,則代碼需要1.25秒執行。 但是,即使我仍然使用net.pipe或net.tcp與之交談,如果我將其放在新的AppDomain中,則該過程仍需要4.7s才能運行。 這是底部注釋欄中帶有app.config的代碼。

namespace ConsoleApplication2
{
    using System;
    using System.Collections.Concurrent;
    using System.Diagnostics;
    using System.Linq;
    using System.Net;
    using System.Net.NetworkInformation;
    using System.Reflection;
    using System.ServiceModel;
    using System.Threading.Tasks;

    using Client;

    internal class Program
    {
        #region Methods

        private static void Main(string[] args)
        {
            var p = new Program();
            p.Execute();
        }

        #endregion

        public void Execute()
        {
            var hosts = Enumerable.Range(0, 1).Select(CreateNewHost).ToArray();
            var r = new Random();
            var cb = new ConcurrentDictionary<int, string>();
            Action a = () =>
            {
                try
                {
                    Parallel.For(
                        0,
                        10000,
                        i =>
                        {
                            //string ep = String.Format("net.pipe://localhost/iService{0}", hosts[r.Next(0, hosts.Length)]);
                            string ep = String.Format("net.tcp://localhost:{0}/iService", hosts[r.Next(0, hosts.Length)]);
                            string s=null;
                            //using (var cli = new ServiceClassClient("NetNamedPipeBinding_IServiceClass", ep))
                            using (var cli = new ServiceClassClient("NetTcpBinding_IServiceClass", ep))
                            {
                                s = cli.Ping();
                            }
                            if (!String.IsNullOrEmpty(s))
                            {
                                cb[i] = s;
                            }
                        });
                }
                catch (AggregateException aggregateException)
                {
                    Console.WriteLine(aggregateException);
                }
            };
            Console.WriteLine("\n\nIt took {0:G}", a.TimeThis());
            Console.ReadKey();
        }

        static int CreateNewHost(int s)
        {
            //uncomment for in-process host
            //var h1 = new Host();
            //return h1.Port;

            var appDomain = AppDomain.CreateDomain(
                "A" + s,
                null,
                new AppDomainSetup
                    {
                        LoaderOptimization = LoaderOptimization.MultiDomain,
                        DisallowBindingRedirects = true
                    });
            var assemblyName = Assembly.GetAssembly(typeof(Host)).FullName;
            var h = appDomain.CreateInstanceAndUnwrap(assemblyName, typeof(Host).FullName) as Host;
            return h.Port;
        }
    }

    //comment out MarshalByRefObject for in-process host
    public class Host:MarshalByRefObject
    {
        #region Fields

        private readonly ServiceHost host;

        private readonly int port;

        #endregion

        #region Constructors and Destructors

        public Host()
        {
            this.port = this.GetFreePort();
            var ub = new UriBuilder { Host = "localhost", Port = this.port, Scheme = "net.tcp" };
            var up = new UriBuilder { Host = "localhost", Scheme = "net.pipe", Path = "iService" + this.port };
            this.host = new ServiceHost(typeof(ServiceClass), ub.Uri);
            var netNamedPipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
            this.host.AddServiceEndpoint(typeof(IServiceClass), netNamedPipeBinding, up.Uri);
            var un = new UriBuilder { Host = "localhost", Port = this.port, Scheme = "net.tcp", Path = "iService" };
            var netTcpBinding = new NetTcpBinding(SecurityMode.None);
            this.host.AddServiceEndpoint(typeof(IServiceClass), netTcpBinding, un.Uri);

//#if DEBUG
            //var us = new UriBuilder { Host = "localhost", Port = this.port, Scheme = "http", Path = "iServiceMeta" };
            //var smb = new ServiceMetadataBehavior { HttpGetEnabled = true, HttpGetUrl = us.Uri };
            //this.host.Description.Behaviors.Add(smb);
//#endif
            this.host.Open();
            Console.WriteLine("Listening at {0}", this.host.BaseAddresses[0].AbsoluteUri);
        }

        #endregion

        #region Public Properties

        public int Port
        {
            get
            {
                return this.port;
            }
        }

        public ServiceHost ServiceHost
        {
            get
            {
                return this.host;
            }
        }

        #endregion

        #region Methods

        private int GetFreePort()
        {
            TcpConnectionInformation[] connections = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections();
            IPEndPoint[] listeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners();
            var udps = IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners();
            var r = new Random();
            int port;
            do
            {
                port = r.Next(1025, 65534);
            }
            while (listeners.Any(a => a.Port == port) || connections.Any(a => a.LocalEndPoint.Port == port) || udps.Any(a=>a.Port==port));
            return port;
        }

        #endregion
    }

    [ServiceContract]
    internal interface IServiceClass
    {
        #region Public Methods and Operators

        [OperationContract]
        string Ping();

        #endregion
    }

    internal class ServiceClass : IServiceClass
    {
        #region Public Methods and Operators

        public string Ping()
        {
            return ((new Random()).NextDouble() * (new Random()).NextDouble()).ToString("F11");
        }

        #endregion
    }

    public static class Extensions
    {
        #region Public Methods and Operators

        public static TimeSpan TimeThis(this Action action)
        {
            var sw = new Stopwatch();
            sw.Start();
            action.Invoke();
            sw.Stop();
            return sw.Elapsed;
        }

        #endregion
    }
}

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.18033
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Client
{

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(ConfigurationName = "IServiceClass")]
    public interface IServiceClass
    {

        [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IServiceClass/Ping", ReplyAction = "http://tempuri.org/IServiceClass/PingResponse")]
        string Ping();
    }

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    public interface IServiceClassChannel : IServiceClass, System.ServiceModel.IClientChannel
    {
    }

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    public partial class ServiceClassClient : System.ServiceModel.ClientBase<IServiceClass>, IServiceClass
    {

        public ServiceClassClient()
        {
        }

        public ServiceClassClient(string endpointConfigurationName)
            : base(endpointConfigurationName)
        {
        }

        public ServiceClassClient(string endpointConfigurationName, string remoteAddress)
            : base(endpointConfigurationName, remoteAddress)
        {
        }

        public ServiceClassClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress)
            : base(endpointConfigurationName, remoteAddress)
        {
        }

        public ServiceClassClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress)
            : base(binding, remoteAddress)
        {
        }

        public string Ping()
        {
            return base.Channel.Ping();
        }
    }
}


/*
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <bindings>
      <netNamedPipeBinding>
        <binding name="NetNamedPipeBinding_IServiceClass">
          <security mode="None" />
        </binding>
      </netNamedPipeBinding>
      <netTcpBinding>
        <binding name="NetTcpBinding_IServiceClass">
          <security mode="None" />
        </binding>
      </netTcpBinding>
    </bindings>
    <client>
      <endpoint address="" binding="netNamedPipeBinding"
          bindingConfiguration="NetNamedPipeBinding_IServiceClass" contract="IServiceClass"
          name="NetNamedPipeBinding_IServiceClass" />
      <endpoint address="" binding="netTcpBinding"
          bindingConfiguration="NetTcpBinding_IServiceClass" contract="IServiceClass"
          name="NetTcpBinding_IServiceClass" />
    </client>
  </system.serviceModel>
</configuration>
*/

通過使用LoaderOptimization屬性裝飾Main方法,可以提高性能。 這在應用程序域之間共享公共資源。

[LoaderOptimization(LoaderOptimization.MultiDomain)]

有關更多詳細信息,請參見此答案

暫無
暫無

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

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