Dot-Net

我應該記憶體 RNGCryptoServiceProvider/RandomNumberGenerator 實例嗎?

  • June 22, 2017

我已經讀過很多次關於Regex類的效率以及呼叫它的靜態方法或記憶體正則表達式實例的重要性。

我想知道如果我RNGCryptoServiceProvider多次實例化該類而不是記憶體該類的單個實例並呼叫GetBytes它,是否可以觀察到相同的問題。

每次我需要一個隨機數時實例化它會稍微簡化我的程式碼,因為我不必擔心一次性實例掛起並IDisposable在一堆類中傳播介面。

我發現的唯一一件事是創建 RNGCryptoServiceProvider 的實例應該非常快,但我仍然希望看到確認以及最佳實踐是什麼。

如果我每次都實例化類而不是使用相同的實例,生成的隨機數是否也會有任何差異?

使用預設建構子的重複構造不應該對性能或隨機性質量產生任何不良影響。

讓我們看一下原始碼…

#if !FEATURE_PAL
       [System.Security.SecuritySafeCritical]  // auto-generated
       public RNGCryptoServiceProvider() : this((CspParameters) null) {} 
#else // !FEATURE_PAL
       public RNGCryptoServiceProvider() { } 
#endif // !FEATURE_PAL 

FEATURE_PAL 指令與 Windows 與非 Windows 平台有關。但是我們不需要知道細節;讓我們看看真實和虛假的案例。

首先,很明顯,如果啟用了 FEATURE_PAL,則預設建構子中沒有程式碼。

在另一種情況下,建構子呼叫具有空 CspParameters 的特定建構子。另一個建構子如下所示:

[System.Security.SecuritySafeCritical]  // auto-generated 
public RNGCryptoServiceProvider(CspParameters cspParams) {
  if (cspParams != null) { 
        m_safeProvHandle = Utils.AcquireProvHandle(cspParams);
        m_ownsHandle = true;
  }
  else { 
        m_safeProvHandle = Utils.StaticProvHandle;
        m_ownsHandle = false; 
  } 
}

cspParams 將始終為空,因此建構子正在獲取Utils.StaticProvHandle. 該吸氣劑看起來像這樣:

#if !FEATURE_PAL 
       [System.Security.SecurityCritical /*auto-generated*/] 
       private static SafeProvHandle _safeProvHandle = null;
       internal static SafeProvHandle StaticProvHandle { 
           [System.Security.SecurityCritical]  // auto-generated
           get {
               if (_safeProvHandle == null) {
                   lock (InternalSyncObject) { 
                       if (_safeProvHandle == null) {
                           SafeProvHandle safeProvHandle = AcquireProvHandle(new CspParameters(DefaultRsaProviderType)); 
                           Thread.MemoryBarrier(); 
                           _safeProvHandle = safeProvHandle;
                       } 
                   }
               }
               return _safeProvHandle;
           } 
       }
#endif // !FEATURE_PAL 

它由靜態變數支持。getter 在第一次初始化期間使用了一些鎖,但隨後的呼叫只返回靜態變數。

現在讓我們回顧一下RNGCryptoServiceProvider.cs,看看Dispose方法:

[System.Security.SecuritySafeCritical]  // auto-generated
protected override void Dispose(bool disposing) {
  base.Dispose(disposing);

  if (disposing && m_ownsHandle) {
        m_safeProvHandle.Dispose(); 
  } 
}

m_ownsHandle如果呼叫了預設建構子,則為 false,因此它永遠不會處理任何內容。

因此,在每次構造+處置期間發生的所有事情都是一些簡單的變數訪問。

引用自:https://stackoverflow.com/questions/26371951