我应该缓存RNGCryptoServiceProvider / RandomNumberGenerator实例吗?

时间:2014-10-14 23:13:09

标签: .net performance caching random cryptography

我已经多次读过Regex类的效率,以及调用它的静态方法或缓存正则表达式实例的重要性。

如果我多次实例化RNGCryptoServiceProvider类而不是缓存类的单个实例并在其上调用GetBytes,我想知道是否可以观察到相同的问题。

每次我需要一个随机数时实例化它会简化我的代码,因为我不必担心一次性实例挂起并在一堆类中传播IDisposable接口。

我唯一发现的是creating an instance of a RNGCryptoServiceProvider should be very fast,但我仍然希望看到确认,最佳做法是什么。

如果每次实例化该类而不是使用相同的实例,那么生成的随机数是否会有任何差异?

1 个答案:

答案 0 :(得分:16)

使用默认构造函数重复构造不应对性能或随机性质量产生任何不良影响。

让我们来看看源代码......

#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,则默认构造函数中没有代码。

在另一种情况下,构造函数使用null 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将始终为null,因此构造函数的值为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,因此它永远不会处置任何内容。

因此,在每个构造+处理期间发生的所有事情都是一些简单的变量访问。

相关问题