首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

動態 WebService 呼叫與靜態代理效能差距實測:3 倍效能落差

     編輯:關於.NET

前言

專案需動態指定 WebService URL,採用「執行時下載 WSDL → 動態編譯組件 → 反射呼叫」方案。實測發現動態呼叫耗時 1.29 秒,靜態代理僅 0.43 秒,效能差距近 3 倍。本文分析根因並探討優化方向。

動態呼叫實作(通用反射方案)

public object InvokeWebservice(string url, string @namespace, string classname, string methodname, object[] args)
{
    WebClient wc = new WebClient();
    Stream stream = wc.OpenRead(url + "?WSDL");
    ServiceDescription sd = ServiceDescription.Read(stream);
    ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
    sdi.AddServiceDescription(sd, "", "");
    
    CodeNamespace cn = new CodeNamespace(@namespace);
    CodeCompileUnit ccu = new CodeCompileUnit();
    ccu.Namespaces.Add(cn);
    sdi.Import(cn, ccu);
    
    CSharpCodeProvider csc = new CSharpCodeProvider();
    ICodeCompiler icc = csc.CreateCompiler();
    CompilerParameters cplist = new CompilerParameters();
    cplist.GenerateInMemory = true;
    cplist.ReferencedAssemblies.AddRange(new[] { "System.dll", "System.Xml.dll", "System.Web.Services.dll", "System.Data.dll" });
    
    CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu);
    if (cr.Errors.HasErrors) throw new Exception(/* 錯誤訊息 */);
    
    Assembly assembly = cr.CompiledAssembly;
    Type t = assembly.GetType(@namespace + "." + classname, true, true);
    object obj = Activator.CreateInstance(t);
    MethodInfo mi = t.GetMethod(methodname);
    return mi.Invoke(obj, args);
}

效能瓶頸分析

  1. 網路下載 WSDL:每次呼叫皆需 HTTP GET 取得 WSDL 文檔。
  2. 解析與 CodeDom 建構:ServiceDescriptionImporter 解析 WSDL、建構 CodeDom 樹。
  3. 動態編譯:CSharpCodeProvider 編譯記憶體組件(含語法分析、IL 生成、JIT)。
  4. 反射呼叫:Activator.CreateInstance、MethodInfo.Invoke 晚繫結開銷。

靜態代理僅有一次性 JIT 開銷,後續呼叫為直接虛擬方法調用。

優化方向:實現「URL 動態、代理靜態」

方案一:預編譯共用代理 + 執行時修改 Endpoint Address

// 專案加入服務參考生成靜態代理類別 MyServiceClient
var client = new MyServiceClient();
client.Endpoint.Address = new EndpointAddress(dynamicUrl); // 執行時指定 URL
client.DoWork();

前提:所有目標服務契約(介面、資料合約)完全一致,僅端點位址不同。

方案二:快取動態編譯組件

  • 以 WSDL URL 為 Key 快取 Assembly 或 ChannelFactory<T>。
  • 首次呼叫耗時 1.29 秒,後續呼叫極速(僅反射開銷)。
  • 需處理 WSDL 版本變更導致的快取失效。

方案三:使用 ChannelFactory<T> 動態建立通道

var binding = new BasicHttpBinding();
var address = new EndpointAddress(dynamicUrl);
var factory = new ChannelFactory(binding, address);
IMyService proxy = factory.CreateChannel();
proxy.DoWork();
((IClientChannel)proxy).Close();

無需 WSDL 下載與編譯,直接依共用介面組件建立通道,效能接近靜態代理。

結語

動態 WebService 呼叫的效能代價主要在「WSDL 下載 → 編譯」管線。若契約固定,強烈建議使用靜態代理 + 動態 Endpoint Address 或 ChannelFactory<T> 方案,兼具彈性與高效能。唯有契約本身動態變化時,才需完整動態編譯流程。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved