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

WCF 同步內容機制深度解析:從 UI 執行緒關聯到自訂執行緒池與優先權處理

     編輯:關於.NET

什麼是 .NET 同步內容

SynchronizationContext(.NET 2.0 引入)定義於 System.Threading,核心成員:

public delegate void SendOrPostCallback(object state);
public class SynchronizationContext
{
    public virtual void Post(SendOrPostCallback callback, object state);  // 非同步
    public virtual void Send(SendOrPostCallback callback, object state);   // 同步
    public static void SetSynchronizationContext(SynchronizationContext context);
    public static SynchronizationContext Current { get; }
}

儲存於執行緒區域儲存區 (TLS),每個執行緒可有一個同步內容。用途:在呼叫執行緒與目標執行緒間封送方法呼叫。

經典應用:UI 更新

Windows Forms / WPF 中,只有建立視窗的 UI 執行緒能更新介面。WindowsFormsSynchronizationContext 將委派轉為 Windows 訊息發送到 UI 訊息佇列,BackgroundWorker 即建構於此機制之上。

WCF 預設行為

  • 服務呼叫在 I/O Completion 執行緒池執行(預設 1000 執行緒)
  • ServiceBehaviorAttribute.UseSynchronizationContext 預設 true
  • 若開啟 ServiceHost 的執行緒有同步內容,WCF 自動將所有呼叫封送至該內容

範例:WinForms 服務自動關聯 UI 執行緒

static void Main()
{
    Form form = new MyForm();  // 此處建立同步內容
    ServiceHost host = new ServiceHost(typeof(MyService));
    host.Open();
    Application.Run(form);     // UI 訊息迴圈
    host.Close();
}

若 host.Open() 在建立 Form 之前,則無法受益於自動關聯。

自訂同步內容:ThreadPoolSynchronizer

將所有呼叫封送至自訂執行緒池,控制併發數量、最大化吞吐量。

實作重點

  1. 繼承 SynchronizationContext,實作 Post/Send 佇列至執行緒池
  2. 透過 IContractBehavior.ApplyDispatchBehavior 將同步內容指派給 DispatchRuntime.SynchronizationContext
  3. 實作 IServiceBehavior.Validate 訂閱 ServiceHostBase.Closed 事件釋放執行緒池
  4. 使用靜態 ThreadPoolHelper 字典對應服務型別到同步器實例,確保多端點共用同一池

宣告式套用

[ThreadPoolBehavior(3, typeof(MyService))]
class MyService : IMyContract { ... }

執行緒親和性

池大小 = 1 時,建立特定執行緒與所有服務呼叫的親和關係。適用場景:

  • 服務需建立/更新 UI(如彈出視窗)
  • 存取使用 TLS 的資源

此時所有服務實例天然執行緒安全,建議搭配 ConcurrencyMode.Single。

專用屬性

[ThreadAffinityBehavior(typeof(MyService))]
class MyService : IMyContract { ... }

優先權處理

預設先進先出。PrioritySynchronizer 依優先權排序佇列:

public enum CallPriority { Low, Normal, High }
public class PrioritySynchronizer : ThreadPoolSynchronizer
{
    public static CallPriority Priority { get; set; }  // TLS 儲存
}

傳遞優先權的挑戰

WCF 客戶端執行緒不直接呼叫服務,無法用 TLS。解決方案:訊息標頭帶外傳遞。

GenericContext<T> 通用標頭機制

[DataContract]
public class GenericContext
{
    [DataMember] public readonly T Value;
    public static GenericContext Current 
    {
        get => OperationContext.Current.IncomingMessageHeaders.GetHeader>(...);
        set => OperationContext.Current.OutgoingMessageHeaders.Add(...);
    }
}

客戶端代理基類封裝

public abstract class HeaderClientBase : ClientBase where T : class
{
    protected H Header;
    protected virtual object Invoke(string operation, params object[] args)
    {
        using (new OperationContextScope(InnerChannel))
        {
            GenericContext.Current = new GenericContext(Header);
            return typeof(T).GetMethod(operation).Invoke(Channel, args);
        }
    }
}

public abstract class PriorityClientBase : HeaderClientBase where T : class
{
    public PriorityClientBase(CallPriority priority) : base(priority) { }
}

使用範例

class MyContractClient : PriorityClientBase, IMyContract
{
    public MyContractClient(CallPriority priority) : base(priority) { }
    public void MyMethod(string text) => Invoke("MyMethod", text);
}

var proxy = new MyContractClient(CallPriority.High);
proxy.MyMethod();

回呼與同步內容

CallbackBehaviorAttribute.UseSynchronizationContext 同樣支援自訂同步內容。關鍵差異:

  • 關聯時機:開啟 Proxy(建立雙工通道)的執行緒
  • 需實作 IEndpointBehavior.ApplyClientBehavior 設定 ClientRuntime.CallbackDispatchRuntime.SynchronizationContext
  • 無 ServiceHost 可訂閱關閉事件,改監聽 AppDomain.CurrentDomain.ProcessExit

回呼執行緒親和性屬性

[CallbackThreadAffinityBehavior(typeof(MyClient))]
class MyClient : IMyContractCallback, IDisposable { ... }

為什麼使用同步內容

  • 以極少程式碼完成困難任務:執行緒親和、優先權處理
  • 所有邏輯在服務範圍之外,符合關注點分離
  • GenericContext<T> 技術適用於任何需帶外參數的 WCF 擴展
  • 展示 WCF 可擴展性威力

同步內容與 WCF 結合,產生出色且高效的程式模型。本文展示的自訂標頭與通用內容技術,在整個 WCF 程式設計領域極具價值。

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