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

WCF 並發處理機制實戰探測:建立監控程式驗證 InstanceContextMode 與 ConcurrencyMode 行為

     編輯:關於.NET

為了直觀理解 WCF InstanceContextMode (單例/每會話/每呼叫) 與 ConcurrencyMode (單一/多重/可重入) 對並發行為的影響,本文實作一個雙端監控程式 (WinForms 寄宿服務 + WinForms 客戶端),即時記錄服務呼叫開始/結束、操作執行開始/結束、回調事件等時間戳與客戶端 ID,視覺化呈現並發處理時間軸。

架構設計

  • 契約層:ICalculator (單一 Add(double, double) 操作)、EventType 列舉 (8 種監控事件)、EventMonitor 靜態類別 (事件發布/訂閱、客戶端 ID 透過訊息標頭傳遞)。
  • 服務層:CalculatorService 標記 [ServiceBehavior(UseSynchronizationContext=false)],Add 方法中 Thread.Sleep(5000) 模擬長時間操作,穿插 EventMonitor.Send(EventType.StartExecute/EndExecute)。
  • 寄宿端 (WinForms):ServiceHost 寄宿,ListBox 即時顯示監控日誌,SynchronizationContext.Post 確保 UI 執行緒安全更新。
  • 客戶端 (WinForms):ThreadPool.QueueUserWorkItem 併發建立 5 個 Proxy,各附帶唯一 ClientID 訊息標頭,呼叫 Add(1,2) 並記錄 StartCall/EndCall。
  • 繫結:ws2007HttpBinding (支援可靠會話與訊息標頭)。

EventMonitor 核心實作

public static class EventMonitor
{
    public const string ClientIdHeaderNamespace = "https://www.artech.com/";
    public const string ClientIdHeaderLocalName = "ClientId";
    public static EventHandler MonitoringNotificationSended;

    public static void Send(EventType eventType) // 服務端用:從標頭取 ClientID
    {
        if (MonitoringNotificationSended != null)
        {
            int clientId = OperationContext.Current.IncomingMessageHeaders.GetHeader(ClientIdHeaderLocalName, ClientIdHeaderNamespace);
            MonitoringNotificationSended(null, new MonitorEventArgs(clientId, eventType, DateTime.Now));
        }
    }

    public static void Send(int clientId, EventType eventType) // 客戶端用:直接指定 ClientID
    {
        if (MonitoringNotificationSended != null)
            MonitoringNotificationSended(null, new MonitorEventArgs(clientId, eventType, DateTime.Now));
    }
}

客戶端併發呼叫關鍵代碼

for (int i = 1; i <= 5; i++)
{
    ThreadPool.QueueUserWorkItem(state =>
    {
        int clientId = Interlocked.Increment(ref clientIdIndex);
        ICalculator proxy = _channelFactory.CreateChannel();
        using (proxy as IDisposable)
        {
            EventMonitor.Send(clientId, EventType.StartCall);
            using (OperationContextScope scope = new OperationContextScope(proxy as IContextChannel))
            {
                var header = new MessageHeader(clientId).GetUntypedHeader(EventMonitor.ClientIdHeaderLocalName, EventMonitor.ClientIdHeaderNamespace);
                OperationContext.Current.OutgoingMessageHeaders.Add(header);
                proxy.Add(1, 2); // 封鎖 5 秒
            }
            EventMonitor.Send(clientId, EventType.EndCall);
        }
    }, null);
}

監控輸出範例:Single + Single (序列化執行)

監控輸出:Client 1 StartCall -> StartExecute -> EndExecute -> EndCall,隨後 Client 2 依序... 總耗時 25 秒

觀察結果:ConcurrencyMode.Single + InstanceContextMode.Single 導致 5 個併發請求在服務端**序列化執行**,總耗時 ≈ 5秒 × 5 = 25秒。

後續驗證計畫

後續文章將系統驗證以下組合差異:

InstanceContextModeConcurrencyMode預期行為
PerCallSingle每請求新實例,並行執行 (無共享狀態衝突)
PerSessionMultiple同會話共享實例,多執行緒並行進入操作,需自行同步
SingleReentrant單實例允許重入 (回調時釋放鎖),適合雙工服務

原始碼下載

完整專案結構 (契約/服務/寄宿/客戶端) 可從文章連結下載,直接編譯執行即可複現實驗。

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