3

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
user9609349
  • 91
  • 2
  • 8
  • 2
    It is not safe to use the same `Random` instance across many threads. – spender Dec 02 '20 at 11:18
  • oh, you are actually right! it's working, Just added a new Random object in the fillpart function. I would like to know why tho – user9609349 Dec 02 '20 at 11:20
  • The trouble now is that you're possibly creating a bunch of Random instances at the same time. So that they don't all spew out the same numbers, you're going to have to add further complexity to ensure that they are seeded differently. – spender Dec 02 '20 at 11:26
  • Does this answer your question? [How to create byte array and fill it with random data](https://stackoverflow.com/questions/54471184/how-to-create-byte-array-and-fill-it-with-random-data) – Sinatr Dec 02 '20 at 11:28
  • no, very much no! the point is to work with threads @Sinatr – user9609349 Dec 02 '20 at 11:38
  • You are possibly suffering from [`false sharing`](https://en.wikipedia.org/wiki/False_sharing). But what happens if you omit the random data and just fill the array with a fixed value? Is it still slower when multithreaded? – Matthew Watson Dec 02 '20 at 12:47
  • Related: [Is C# Random Number Generator thread safe?](https://stackoverflow.com/questions/3049467/is-c-sharp-random-number-generator-thread-safe) – Theodor Zoulias Dec 02 '20 at 12:57

2 Answers2

5

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.

spender
  • 117,338
  • 33
  • 229
  • 351
0

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);
        }
MichaelMao
  • 2,596
  • 2
  • 23
  • 54
  • See my comment above about seeding the Random so the resulting array doesn't repeat itself. – spender Dec 02 '20 at 12:11
  • I think his problem is not about unique number is about thread performance. But your are right I was inspired by your comment – MichaelMao Dec 02 '20 at 12:14