问题描述
注意到,在以上的多个线程并行生成随机数,当加密的随机数发生器不是线程安全。使用的发电机 RNGCryptoServiceProvider
,它似乎重复随机位(128位)长的舒展。复制此代码如下所示。
Noticed that the crypto-random number generator isn't thread safe when generating random numbers in parallel over multiple threads. The generator used is RNGCryptoServiceProvider
and it appears to repeat long stretches of random bits (128 bits). The code to reproduce this is shown below.
用锁来保护访问 RNGCryptoServiceProvider
实例短( ?它可以杀死这里的整个速度点),没有任何人有到发电机加密的随机数更快的方法
Short of using a lock to guard access to the RNGCryptoServiceProvider
instance (which kills the whole speed point here), does anyone have a faster way to generator crypto-random numbers?
using System;
using System.Runtime.Caching;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace ParallelRandomness
{
class Program
{
static void Main(string[] args)
{
var test = new Test();
Console.Write("Serialized verion running ... ");
test.Run(false);
Console.WriteLine();
Console.Write("Parallelized verion running ... ");
test.Run(true);
Console.WriteLine(Environment.NewLine + "Done.");
Console.ReadLine();
}
}
class Test
{
private readonly RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
private readonly byte[] _randomBytes = new byte[128 / 8];
private int collisionCount = 0;
private readonly object collisionCountLock = new object();
public void Run(bool parallel)
{
const int numOfRuns = 100000;
const int startInclusive = 1;
const int endExclusive = numOfRuns + startInclusive;
if (parallel)
Parallel.For(startInclusive, endExclusive, x => GenRandomByteArrays(x));
else
{
for (var i = startInclusive; i < endExclusive; i++)
GenRandomByteArrays(i);
}
}
private void GenRandomByteArrays(long instance)
{
_rng.GetBytes(_randomBytes);
var randomString = Convert.ToBase64String(_randomBytes);
var cache = MemoryCache.Default;
if (cache.Contains(randomString))
{
// uh-oh!
lock (collisionCountLock)
{
Console.WriteLine(Environment.NewLine + "Instance {0}: Collision count={1}. key={2} already in cache. ", instance, ++collisionCount, randomString);
}
}
else
{
MemoryCache.Default.Add(randomString, true, DateTimeOffset.UtcNow.AddMinutes(5));
Console.Write(instance % 2 == 0 ? "\b-" : "\b|"); // poor man's activity indicator
}
}
}
}
推荐答案
的 RNGCryptoServiceProvider
规定:
这类型是线程安全的。
您的代码不表明 RNGCryptoServiceProvider
不是线程安全的,因为你使用多个线程在同一阵列。这阵再利用是不是线程安全的,即使 RNGCryptoServiceProvider
是
Your code doesn't demonstrate that RNGCryptoServiceProvider
is not thread-safe, since you use the same array in multiple threads. That array reuse is not thread-safe even if RNGCryptoServiceProvider
is.
对于性能我想指出,创建 RNGCryptoServiceProvider
的新实例是非常便宜的。昂贵的部分是 GetBytes会
的每个调用的开销。
Regarding performance I want to note that creating a new instance of RNGCryptoServiceProvider
is very cheap. The expensive part is the per-call overhead of GetBytes
.
所以,如果你有性能问题,请第一件事我想尝试一次过被要求更多的数据和自己分裂它。如果这还不够,使用系统CSPRNG种子流密码。
So if you have performance trouble, the first thing I'd try is asking for more data in one go and splitting it yourself. If that's still not enough, use a stream cipher seeded by the system CSPRNG.
这篇关于最快,线程安全的方式来创建在C#中加密的随机数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!