当托管在另一个AppDomain时,WCF主机速度很慢

本文关键字:主机 WCF 速度 另一个 AppDomain | 更新日期: 2023-09-27 18:14:48

我有一个奇怪的问题。如果WCF主机托管在原始AppDomain中,则代码执行时间为1.25秒。然而,如果我把它放在一个新的AppDomain,尽管我仍然使用net。管或网。TCP与它通信,该进程需要4.7秒才能运行。下面是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>
*/

当托管在另一个AppDomain时,WCF主机速度很慢

用LoaderOptimization属性修饰Main方法可以提高性能。这在应用程序域之间共享公共资源。

[LoaderOptimization(LoaderOptimization.MultiDomain)]