在c#中创建加密随机数的最快,线程安全的方法?

Dee*_*101 2 c# random parallel-processing multithreading cryptography

注意到在多线程上并行生成随机数时,加密随机数生成器不是线程安全的.使用的生成器RNGCryptoServiceProvider似乎重复了很长的随机位(128位).重现此代码的代码如下所示.

如果没有使用锁来保护对RNGCryptoServiceProvider实例的访问(这会杀死整个速度点),有没有人有更快的方法来生成加密随机数?

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
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Cod*_*aos 7

RNGCryptoServiceProvider各州的文件:

这种类型是线程安全的.

您的代码未演示RNGCryptoServiceProvider不是线程安全的,因为您在多个线程中使用相同的数组.即使RNGCryptoServiceProvider是,该数组重用也不是线程安全的.

关于性能我想要注意,创建一个新实例RNGCryptoServiceProvider是非常便宜的.昂贵的部分是每次呼叫的开销GetBytes.

因此,如果您遇到性能问题,我首先要尝试的是一次性请求更多数据并自行拆分.如果仍然不够,请使用系统CSPRNG播种的流密码.