插件系统中跨域调用的性能和"一个简单的性能计数器"的使用

it2025-01-20  29

请到此处下载代码

    系统大概的流程如下:从数据中心接收到数据包(1万~3万(个)/秒,使用WCF)可以被不同的应用场景使用,每个应用场景的业务逻辑各不相同,而每个场景的接收数据包部分的代码是相同的,于是使用一个容器将所有的"应用场景的dll"通过反射加载,同时容器接收所有的数据包并把他们分发给"应用场景的dll",接收数据的功能,自然被抽象成了Interface。透彻一点讲就是一个插件系统,只不过这个插件有点儿大而已,大到整个系统都是个插件。这个容器我们暂时叫他“引擎”,而这个"场景的dll"我们暂且叫他“规则”。

     我的理想做法是:每一个规则(一个或多个dll)都单独放在一个文件夹下面,并且有自己的配置文件。当引擎启动的时候,根据引擎的配置为每个规则创建一个新的AppDomain,并且还为该AppDomain设置配置文件,同时让这个新的AppDomain加载相对应的dll。引擎的CurrentDomain里面保存着每个规则的MarshalByRefObject,当引擎接收到数据的时候,就把这些数据根据一些条件分发到相对应的规则当中。俄,引擎看起来有点像一个IIS啊!!!

           

                    

    等等,这么美妙的想法,这么容易就可以实现?! 我是不是忘记了什么??哦 我忘记了那些规则的MarshalByRefObject每秒钟是否能承受1万~3万次的调用(这里的调用就是传递数据包)。

     [下午系统测试得时候,性能技术器显示每秒钟仅仅2千个左右的包被处理,剩下的都丢了。。。。。。疯狂的郁闷中]

 

     自从上次net技术大会回来,每天都挺忙,好多讲课还没来得及回味,看到老赵和eaglet都CodeTimer了,惭愧啊,不过刚好拿过来用吧。测试代码如下:

 1。FunA() FunB() FunC() FunD() 为测试代码,class RemoterProxy是为了创建远程对象更容易一些,不是Proxy模式哦。

Code  1namespace AppDomainPerformanceDemo 2{ 3    class Program 4    { 5        const int COUNT = 500000; 6 7        static void Main( string[] args ) 8        { 9            FunA();10            FunB();11            FunC();12            FunD();1314            Console.ReadLine();15        }1617        18        static void FunC()19        {20            RemoterProxy remoterProxy = new RemoterProxy();21            CodeTimer.Time( "RemoterProxy:  Same AppDomain", COUNT, remoterProxy.FunTest );22        }2324        static void FunD()25        {26            AppDomain domain = AppDomain.CreateDomain( "NewAppDomain" );27            RemoterProxy remoterProxy = (RemoterProxy)domain.CreateInstanceAndUnwrap( Assembly.GetExecutingAssembly().FullName, "AppDomainPerformanceDemo.RemoterProxy" ); ;28            CodeTimer.Time( "RemoterProxy:  Across AppDomain", COUNT, remoterProxy.FunTest );29            AppDomain.Unload( domain );30        }3132        static void FunB()33        {34            IInterface inter = new ImplementA();35            CodeTimer.Time( "ImplementA:  Same AppDomain", COUNT, inter.FunA );36        }3738        static void FunA()39        {40            AppDomain domain = AppDomain.CreateDomain( "NewAppDomain" );41            RemoterProxy remoterProxy = (RemoterProxy)domain.CreateInstanceAndUnwrap( Assembly.GetExecutingAssembly().FullName, "AppDomainPerformanceDemo.RemoterProxy" );;42            IInterface inter = remoterProxy.CreateInstance( "AppDomainPerformanceDemo.ImplementA""MyImplement", BindingFlags.CreateInstance, null );43            CodeTimer.Time( "ImplementA:  Across AppDomain", COUNT, inter.FunA );44            AppDomain.Unload( domain );45        46        }47    }4849    public class RemoterProxy : MarshalByRefObject50    {51        public IInterface CreateInstance( string typeName, string assemblyName, BindingFlags bindingFlags, object[] constructorParams )52        {53            Assembly owningAssembly = Assembly.Load( assemblyName );5455            IInterface instanceHandler = owningAssembly.CreateInstance( typeName) as IInterface;//, false, bindingFlags, null, constructorParams, null, null ) as IInterface;5657            return instanceHandler;58        }5960        public void FunTest()61        {62        }63    }6465    66}67

2。CodeTimer使用eaglet的,但是把IAction修改了。(我的机器是xp,vs2008)

Code  1namespace AppDomainPerformanceDemo 2{ 3    public static class CodeTimer 4    { 5        [DllImport( "kernel32.dll", SetLastError = true )] 6        static extern bool GetThreadTimes( IntPtr hThread, out long lpCreationTime, 7           out long lpExitTime, out long lpKernelTime, out long lpUserTime ); 8 9        [DllImport( "kernel32.dll" )]10        static extern IntPtr GetCurrentThread();1112        private static long GetCurrentThreadTimes()13        {14            long l;15            long kernelTime, userTimer;16            GetThreadTimes( GetCurrentThread(), out l, out l,17                out kernelTime, out userTimer );18            return kernelTime + userTimer;19        }2021        static CodeTimer()22        {23            Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;24            Thread.CurrentThread.Priority = ThreadPriority.Highest;2526        }2728        public static void Time( string name, int iteration, Action action )29        {30            if( String.IsNullOrEmpty( name ) )31            {32                return;33            }3435            if( action == null )36            {37                return;38            }3940            // 1.41            ConsoleColor currentForeColor = Console.ForegroundColor;42            Console.ForegroundColor = ConsoleColor.Yellow;43            Console.WriteLine( name );4445            // 2.46            GC.Collect( GC.MaxGeneration, GCCollectionMode.Forced );47            int[] gcCounts = new int[GC.MaxGeneration + 1];48            forint i = 0; i <= GC.MaxGeneration; i++ )49            {50                gcCounts[i] = GC.CollectionCount( i );51            }5253            // 3.54            Stopwatch watch = new Stopwatch();55            watch.Start();56            long ticksFst = GetCurrentThreadTimes(); //100 nanosecond one tick5758            forint i = 0; i < iteration; i++ ) action();59            long ticks = GetCurrentThreadTimes() - ticksFst;60            watch.Stop();6162            // 4.63            Console.ForegroundColor = currentForeColor;64            Console.WriteLine( "\tTime Elapsed:\t" +65               watch.ElapsedMilliseconds.ToString( "N0" ) + "ms" );6667            Console.WriteLine( "\tCall:        \t" +68                (iteration/watch.ElapsedMilliseconds)*1000 + "/s" );697071            Console.WriteLine( "\tCPU time:\t" + ticks.ToString( "N0" ) + "ns" );7273            // 5.74            forint i = 0; i <= GC.MaxGeneration; i++ )75            {76                int count = GC.CollectionCount( i ) - gcCounts[i];77                Console.WriteLine( "\tGen " + i + ": \t\t" + count );78            }7980            Console.WriteLine();8182        }83    }8485}

 3。ImplementA是模拟的"规则"

Code  1namespace AppDomainPerformanceDemo 2{ 3    public class ImplementA : MarshalByRefObject, IInterface 4    { 5        IInterface 成员#region IInterface 成员 6 7        public void FunA() 8        { 9            10        }1112        #endregion13    }14}

 4。IInterface模拟的向规则传递数据时的接口

Code 1namespace AppDomainPerformanceDemo2{3    public interface IInterface4    {5        void FunA();6    }7}

 

测试结果如下:

 

 

当时考虑MarshalByRefObject的性能的时候,大概有三点

1。调用函数本身执行的时间,这里ImplementA的FunA函数的函数体是空的。故不考虑。

2。调用函数的时候,输入和输出参数序列化的时间,这里FunA输入和输出参数都是void,故不考虑。

3。方法跨域调用的时间----这个测试主要针对这个。

 

我非常奇怪的就是为何ImplementA和RemoterProxy的在Across AppDomain方式下调用方法的速度为何不同??

望各位大牛多多拍砖,望大牛们下载一下代码,给小的解答一下上面的问题。

 

转载于:https://www.cnblogs.com/StevenChennet/archive/2009/03/11/Steven.html

最新回复(0)