fill an array with random numbers using threads in c#

Viewed 170

so as said in the tile I'm trying to fill up an array of bytes with random numbers using 16 (in my case) threads, now it takes about six and a half seconds filling up an array with 500000000 bytes using one thread so the logic says that using 16 threads will be at least 10 times faster but then I tried to do this, it took 15 seconds to fill it up, what I did is I gave each thread one segment to fill in the same array

here is the code:

        static byte[] nums2 = new byte[500000000];
        static Random rnd = new Random(123);
        static void fill()
        {
            for (int i = 0; i < nums.Length; i++)
                nums[i] = (byte)rnd.Next(10);
        }

        static void fillPart(object ID)
        {
            var part = nums2.Length / Environment.ProcessorCount;
            int baseN = (int)ID * part;
            for (int i = baseN; i < baseN + part; i++)
                nums2[i] = (byte)rnd.Next(10);
            Console.WriteLine("Done! " + ID);
        }

        static void Main(string[] args)
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            fill();
            watch.Stop();
            Console.WriteLine("it took " + watch.Elapsed);
            Console.WriteLine();

            watch.Reset();
            watch.Start();
            Thread[] threads = new Thread[Environment.ProcessorCount];
            for (int i = 0; i < Environment.ProcessorCount; i++)
            {
                threads[i] = new Thread(fillPart);
                threads[i].Start(i);
            }
            for(int i = 0; i < Environment.ProcessorCount; i++)
                threads[i].Join();

            watch.Stop();
            Console.WriteLine("it took " + watch.Elapsed);
        }
    }```
would like to understand why is it took 15 seconds or maybe what I did wrong
2 Answers

If it were me, I'd just:

byte[] nums = new byte[500000000];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(nums);

and be done with it.

If you really want threads:

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
var dop = 8;
var batchSize = 500000000 / dop;
var bigBytes = Enumerable.Range(0, dop).AsParallel().SelectMany(t => {
    var bytes = new byte[batchSize];
    rng.GetBytes(bytes); //This *IS* thread-safe
    return bytes;
}).ToArray();

but I suspect the time spent collating into a new array by SelectMany followed by ToArray might make this more expensive that the single-thread approach.

The problem is you declare the static Random rnd = new Random(int.MaxValue); If you create the Random instance in fillPart method then the program will finish in one second so the problem in not Thread is rnd.Next(10)

        static void fillPart(object ID)
        {            
            Random rnd = new Random(123);

            var part = nums2.Length / Environment.ProcessorCount;
            int baseN = (int)ID * part;
            int co = 0;
            for (int i = baseN; i < baseN + part; i++)
            {
                nums2[i] = (byte)rnd.Next(10);
            }

            //Console.WriteLine("Done! " + ID + co);
        }
Related