mercredi 24 janvier 2018

Using Random in Parallel.For

My program performs many simulations, each of which calls for many random numbers to be generated. The serial method is straightforward and works. However, in my pursuit of parallelizing the work I believe I found a more straightforward method than what I could find. The other methods are somewhat dated.

Am I missing something that will make my method susceptible to any of the myriad of multithreading problems? I ask this because my software is not benefiting from my addition and I am wondering if I missed a problem. My method uses the ability of a Parallel.For to instantiate a variable for individual thread use. In this case each thread gets its own Random.

Timing:

My method: 4s

Stephen: 14s

Jon: 16s

Clearly I don't know as much as Stephen or Jon so I'm concerned I missed something.

My method:

Random rnd = new Random();
int trials = 1_000_000;

ParallelOptions po = new ParallelOptions();
po.MaxDegreeOfParallelism = 4;

await Task.Run(() =>
{
    Parallel.For<Random>(0, trials, po, () => new Random(rnd.Next()), (i, loop, local) =>
    {
        for (int work = 0; work < 1000; work++)
        {
            local.Next();
        }

        return local;
    },
        (x) => { }
    );
});

This next method is by Stephen Toub on the MSDN Blog:

public static class RandomGen2
{
    private static Random _global = new Random();
    [ThreadStatic]
    private static Random _local;

    public static int Next()
    {
        Random inst = _local;
        if (inst == null)
        {
            int seed;
            lock (_global) seed = _global.Next();
            _local = inst = new Random(seed);
        }
        return inst.Next();
     }
}

await Task.Run(() =>
{
    Parallel.For(0, trials, i =>
    {
        for (int work = 0; work < 1000; work++)
        {
            RandomGen2.Next();
        }
    });

});

This next method is by Jon Skeet on his blog:

public static class ThreadLocalRandom
{
    private static readonly Random globalRandom = new Random();
    private static readonly object globalLock = new object();

    private static readonly ThreadLocal<Random> threadRandom = new ThreadLocal<Random>(NewRandom);

    public static Random NewRandom()
    {
        lock (globalLock)
        {
            return new Random(globalRandom.Next());
        }
    }

    public static Random Instance { get { return threadRandom.Value; } }

    public static int Next()
    {
        return Instance.Next();
    }
}

await Task.Run(() =>
{
    Parallel.For(0, trials, i =>
    {
        for (int work = 0; work < 1000; work++)
        {
            ThreadLocalRandom.Instance.Next();
        }
    });
});




Aucun commentaire:

Enregistrer un commentaire