我们可以再次(如在相关问题中)看源代码来得出一些结论(SecureRandom源代码供参考)。
在构造函数中的所有工作去创造伪随机生成:
private static DigestRandomGenerator CreatePrng(string digestName, bool autoSeed)
{
IDigest digest = DigestUtilities.GetDigest(digestName);
if (digest == null)
return null;
DigestRandomGenerator prng = new DigestRandomGenerator(digest);
if (autoSeed)
{
prng.AddSeedMaterial(NextCounterValue());
prng.AddSeedMaterial(GetNextBytes(Master, digest.GetDigestSize()));
}
return prng;
}
创建摘要(散)支付任何费用(相对于其他工作)。例如默认使用的Sha256Digest
(带空构造函数)只分配小的byte[]
缓冲区。创建DigestRandomGenerator
本身也没有花费(几个小缓冲区)。主要完成的工作是:
prng.AddSeedMaterial(GetNextBytes(Master, digest.GetDigestSize()));
它使用“主”RNG生成种子值。完整的.NET平台上的主RNG为RNGCryptoServiceProvider
(其中SecureRandom
存储在静态字段中并仅初始化一次)。因此,在创建SecureRandom
时,所有工作都会为伪RNG创建加密随机种子。
我想说,最好不要每次都创建一个新实例,至少对于小一代(对于一个二代的NextInt()
调用)来说,因为如果您为每个生成的数字创建新实例 - 基本上会使成本加倍(一次为种子生成密码随机数,另一次生成目标随机数)。因为(据我所知),SecureRandom
是线程安全的 - 没有太多理由不重用一个实例。
附注 - 我不认为RNGCryptoServiceProvider
重要创建您的链接声称。它的构造是这样的:
public RNGCryptoServiceProvider()
: this((CspParameters) null)
{
}
[SecuritySafeCritical]
public RNGCryptoServiceProvider(CspParameters cspParams)
{
if (cspParams != null)
{
this.m_safeProvHandle = Utils.AcquireProvHandle(cspParams);
this.m_ownsHandle = true;
}
else
{
// we are interested in this path
this.m_safeProvHandle = Utils.StaticProvHandle;
this.m_ownsHandle = false;
}
}
所以,当你创建新的实例(不提供CSP) - 它重复使用相同的Utils.StaticProvHandle
,所以它使用RNG提供的相同的“非托管”的实例。这又意味着创建新实例并重新使用同一个实例在性能上没有差异。也许在以前的.NET版本中,它不是这样的,不确定。
来源
2017-10-17 17:07:38
Evk
相关(因为它也是关于如何正确使用这个类的未公开基础知识):https://stackoverflow.com/q/46792243/1709587 –
我认为这取决于你需要一个随机数在实践中。在我自己的一个项目中,我使用'RNGCryptoServiceProvider.Create()'为每个站点的新用户生成一个会话标记,并且性能每天处理1,000次访问。那么你多久需要一个随机数? – DiskJunky
从您评论中链接的答案中,您将最终为每个SecureRandom实例实例化一个新的RNGCryptoServiceProvider。除了这种性能打击,它看起来很好。 –