系統大概的流程如下:從數據中心接收到數據包(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模式哦。
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();
13
14 Console.ReadLine();
15 }
16
17
18 static void FunC()
19 {
20 RemoterProxy remoterProxy = new RemoterProxy();
21 CodeTimer.Time( "RemoterProxy: Same AppDomain", COUNT, remoterProxy.FunTest );
22 }
23
24 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 }
31
32 static void FunB()
33 {
34 IInterface inter = new ImplementA();
35 CodeTimer.Time( "ImplementA: Same AppDomain", COUNT, inter.FunA );
36 }
37
38 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 }
48
49 public class RemoterProxy : MarshalByRefObject
50 {
51 public IInterface CreateInstance( string typeName, string assemblyName, BindingFlags bindingFlags, object[] constructorParams )
52 {
53 Assembly owningAssembly = Assembly.Load( assemblyName );
54
55 IInterface instanceHandler = owningAssembly.CreateInstance( typeName) as IInterface;//, false, bindingFlags, null, constructorParams, null, null ) as IInterface;
56
57 return instanceHandler;
58 }
59
60 public void FunTest()
61 {
62 }
63 }
64
65
66}
67
2。CodeTimer使用eaglet的,但是把IAction修改了。(我的機器是xp,vs2008)
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(); 11 12 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 } 20 21 static CodeTimer() 22 { 23 Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High; 24 Thread.CurrentThread.Priority = ThreadPriority.Highest; 25 26 } 27 28 public static void Time( string name, int iteration, Action action ) 29 { 30 if( String.IsNullOrEmpty( name ) ) 31 { 32 return; 33 } 34 35 if( action == null ) 36 { 37 return; 38 } 39 40 // 1. 41 ConsoleColor currentForeColor = Console.ForegroundColor; 42 Console.ForegroundColor = ConsoleColor.Yellow; 43 Console.WriteLine( name ); 44 45 // 2. 46 GC.Collect( GC.MaxGeneration, GCCollectionMode.Forced ); 47 int[] gcCounts = new int[GC.MaxGeneration + 1]; 48 for( int i = 0; i <= GC.MaxGeneration; i++ ) 49 { 50 gcCounts[i] = GC.CollectionCount( i ); 51 } 52 53 // 3. 54 Stopwatch watch = new Stopwatch(); 55 watch.Start(); 56 long ticksFst = GetCurrentThreadTimes(); //100 nanosecond one tick 57 58 for( int i = 0; i < iteration; i++ ) action(); 59 long ticks = GetCurrentThreadTimes() - ticksFst; 60 watch.Stop(); 61 62 // 4. 63 Console.ForegroundColor = currentForeColor; 64 Console.WriteLine( "\tTime Elapsed:\t" + 65 watch.ElapsedMilliseconds.ToString( "N0" ) + "ms" ); 66 67 Console.WriteLine( "\tCall: \t" + 68 (iteration/watch.ElapsedMilliseconds)*1000 + "/s" ); 69 70 71 Console.WriteLine( "\tCPU time:\t" + ticks.ToString( "N0" ) + "ns" ); 72 73 // 5. 74 for( int i = 0; i <= GC.MaxGeneration; i++ ) 75 { 76 int count = GC.CollectionCount( i ) - gcCounts[i]; 77 Console.WriteLine( "\tGen " + i + ": \t\t" + count ); 78 } 79 80 Console.WriteLine(); 81 82 } 83 } 84 85}
3。ImplementA是模擬的"規則"
1namespace AppDomainPerformanceDemo 2{ 3 public class ImplementA : MarshalByRefObject, IInterface 4 { 5 IInterface 成員#region IInterface 成員 6 7 public void FunA() 8 { 9 10 } 11 12 #endregion 13 } 14}
4。IInterface模擬的向規則傳遞數據時的接口
1namespace AppDomainPerformanceDemo 2{ 3 public interface IInterface 4 { 5 void FunA(); 6 } 7}
測試結果如下:
當時考慮MarshalByRefObject的性能的時候,大概有三點
1。調用函數本身執行的時間,這裡ImplementA的FunA函數的函數體是空的。故不考慮。
2。調用函數的時候,輸入和輸出參數序列化的時間,這裡FunA輸入和輸出參數都是void,故不考慮。
3。方法跨域調用的時間----這個測試主要針對這個。
我非常奇怪的就是為何ImplementA和RemoterProxy的在Across AppDomain方式下調用方法的速度為何 不同??
望各位大牛多多拍磚,望大牛們下載一下代碼,給小的解答一下上面的問題。
隨文源碼:http://www.bianceng.net/dotnet/201212/661.htm