C#随机数生成器线程安全吗?

发布于 2025-01-25 01:34:35 字数 217 浏览 1 评论 0原文

是c#'s rando> rando> rando> randy.next() 方法线程安全吗?

Is C#'s Random.Next() method thread safe?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

飘逸的'云 2025-02-01 01:34:36

有关线程安全的随机数生成器,请查看。从文档中:

线程安全

这种类型是线程安全的。

For a thread safe random number generator look at RNGCryptoServiceProvider. From the docs:

Thread Safety

This type is thread safe.

旧故 2025-02-01 01:34:36

我刚刚在螺纹上同时创建了随机实例,并从结果中获得了意外的模式,因为大概所有种子都是相同的。

我的解决方案是创建一个线程安全类 -

  public class StaticRandom
    {
        static Random rnd = new Random();

        public static int GetNext()
        {
            // random is not properly thread safe
            lock(rnd)
            {
                return rnd.Next();
            }
        }
    }

然后,为每个线程创建一个新的随机对象实例 -

// Take this threads instance seed from the static global version
Random rnd = new Random(StaticRandom.GetNext());

I just created Random instance on a load of threads simultaneously and got unexpected patterns from the results because, presumably, all the seeds were the same.

My solution was to create a thread safe class -

  public class StaticRandom
    {
        static Random rnd = new Random();

        public static int GetNext()
        {
            // random is not properly thread safe
            lock(rnd)
            {
                return rnd.Next();
            }
        }
    }

And then, create a new Random object instance for each thread -

// Take this threads instance seed from the static global version
Random rnd = new Random(StaticRandom.GetNext());
蓝天 2025-02-01 01:34:36

这是使用threadlocal的有效解决方案:

public class ThreadSafeRandom
{
    private static readonly Random _global = new Random();
    private static readonly ThreadLocal<Random> _local = new ThreadLocal<Random>(() =>
    {
        int seed;
        lock (_global)
        {
            seed = _global.Next();
        }
        return new Random(seed);
    });

    public static Random Instance => _local.Value;
}

要使用,替换:

var random = new Random();
var myNum = random.Next();

与:

var myNum = ThreadSafeRandom.Instance.Next();

此解决方案已包装为 nuget软件包

编辑:自.NET 6.0以来,您可以使用randy.shared.next()而不是使用。您仍然可以使用上述软件包,该软件包在上面的代码或随机中使用预处理器指令。

Here's an efficient solution using ThreadLocal:

public class ThreadSafeRandom
{
    private static readonly Random _global = new Random();
    private static readonly ThreadLocal<Random> _local = new ThreadLocal<Random>(() =>
    {
        int seed;
        lock (_global)
        {
            seed = _global.Next();
        }
        return new Random(seed);
    });

    public static Random Instance => _local.Value;
}

To use, replace:

var random = new Random();
var myNum = random.Next();

With:

var myNum = ThreadSafeRandom.Instance.Next();

This solution has been packaged as a NuGet package with source available on GitHub.

EDIT: Since .NET 6.0 you can use Random.Shared.Next() instead. You can still use the above package which chooses between the above code or Random.Shared with preprocessor directives.

关于从前 2025-02-01 01:34:36

这是 blueraja的答案作为静态课程的静态类,并实现了所有公共随机成员。

/// <summary>
/// A pseudo-random number generator based on <see cref="Random"/>, but with the following enhancements:
/// <list type="number">
/// <item>Can be safely used from any thread without defaulting to 0.</item>
/// <item>Repeated calls from different threads do not tend to generate identical sequences.</item>
/// </list>
/// </summary>
public static class ThreadSafeRandom
{
    private static readonly Random _globalSeeder = new Random();

    /// <summary>
    /// Holds a separate <see cref="Random"/> instance for each thread.
    /// </summary>
    [ThreadStatic] private static Random _threadStaticInstance;

    /// <summary>
    /// Seeds each thread's <see cref="_threadStaticInstance"/> with <see cref="_globalSeeder"/>'s <see cref="Random.Next()"/>.
    /// Simply using <see langword="new"/> <see cref="Random()"/> would cause a problem where,
    /// if multiple threads' <see cref="Random"/> instances were constructed very close in time,
    /// they would end up with the same seed, and therefore identical sequences.
    /// </summary>
    private static Random GetThreadStaticInstance()
    {
        if (_threadStaticInstance == null)
        {
            int seed;
            lock (_globalSeeder)
            {
                seed = _globalSeeder.Next();
            }

            _threadStaticInstance = new Random(seed);
        }

        return _threadStaticInstance;
    }

    /// <inheritdoc cref="Random.Next()"/>
    public static int Next() => GetThreadStaticInstance().Next();

    /// <inheritdoc cref="Random.Next(int, int)"/>
    public static int Next(int minValue, int maxValue) => GetThreadStaticInstance().Next(minValue, maxValue);

    /// <inheritdoc cref="Random.Next(int)"/>
    public static int Next(int maxValue) => GetThreadStaticInstance().Next(maxValue);

    /// <inheritdoc cref="Random.NextDouble()"/>
    public static double NextDouble() => GetThreadStaticInstance().NextDouble();

    /// <inheritdoc cref="Random.NextBytes(byte[])"/>
    public static void NextBytes(byte[] buffer) => GetThreadStaticInstance().NextBytes(buffer);

Here is an expanded version of BlueRaja's answer as a static class with comments and all public Random members implemented.

/// <summary>
/// A pseudo-random number generator based on <see cref="Random"/>, but with the following enhancements:
/// <list type="number">
/// <item>Can be safely used from any thread without defaulting to 0.</item>
/// <item>Repeated calls from different threads do not tend to generate identical sequences.</item>
/// </list>
/// </summary>
public static class ThreadSafeRandom
{
    private static readonly Random _globalSeeder = new Random();

    /// <summary>
    /// Holds a separate <see cref="Random"/> instance for each thread.
    /// </summary>
    [ThreadStatic] private static Random _threadStaticInstance;

    /// <summary>
    /// Seeds each thread's <see cref="_threadStaticInstance"/> with <see cref="_globalSeeder"/>'s <see cref="Random.Next()"/>.
    /// Simply using <see langword="new"/> <see cref="Random()"/> would cause a problem where,
    /// if multiple threads' <see cref="Random"/> instances were constructed very close in time,
    /// they would end up with the same seed, and therefore identical sequences.
    /// </summary>
    private static Random GetThreadStaticInstance()
    {
        if (_threadStaticInstance == null)
        {
            int seed;
            lock (_globalSeeder)
            {
                seed = _globalSeeder.Next();
            }

            _threadStaticInstance = new Random(seed);
        }

        return _threadStaticInstance;
    }

    /// <inheritdoc cref="Random.Next()"/>
    public static int Next() => GetThreadStaticInstance().Next();

    /// <inheritdoc cref="Random.Next(int, int)"/>
    public static int Next(int minValue, int maxValue) => GetThreadStaticInstance().Next(minValue, maxValue);

    /// <inheritdoc cref="Random.Next(int)"/>
    public static int Next(int maxValue) => GetThreadStaticInstance().Next(maxValue);

    /// <inheritdoc cref="Random.NextDouble()"/>
    public static double NextDouble() => GetThreadStaticInstance().NextDouble();

    /// <inheritdoc cref="Random.NextBytes(byte[])"/>
    public static void NextBytes(byte[] buffer) => GetThreadStaticInstance().NextBytes(buffer);

更新:不是。您需要在调用.next()方法时锁定某些“信号量”对象的每个连续调用的随机实例,或者在每个呼叫上使用具有保证随机种子的新实例。如Yassir所建议,您可以通过在.NET中使用密码学来获得保证的不同种子。

UPDATED: It is not. You need to either reuse an instance of Random on each consecutive call with locking some "semaphore" object while calling the .Next() method or use a new instance with a guaranteed random seed on each such call. You can get the guaranteed different seed by using cryptography in .NET as Yassir suggested.

海的爱人是光 2025-02-01 01:34:36

传统 thread nore noreferrer“> thread thread local Storage方法可以是通过对种子使用无锁算法来改进。以下是从Java的算法中毫无耻辱的(甚至可能上):

public static class RandomGen2 
{
    private static readonly ThreadLocal<Random> _rng = 
                       new ThreadLocal<Random>(() => new Random(GetUniqueSeed()));

    public static int Next() 
    { 
        return _rng.Value.Next(); 
    } 

    private const long SeedFactor = 1181783497276652981L;
    private static long _seed = 8682522807148012L;

    public static int GetUniqueSeed()
    {
        long next, current;
        do
        {
            current = Interlocked.Read(ref _seed);
            next = current * SeedFactor;
        } while (Interlocked.CompareExchange(ref _seed, next, current) != current);
        return (int)next ^ Environment.TickCount;
   } 
}

The traditional thread local storage approach can be improved upon by using a lock-less algorithm for the seed. The following was shamelessly stolen from Java's algorithm (possibly even improving on it):

public static class RandomGen2 
{
    private static readonly ThreadLocal<Random> _rng = 
                       new ThreadLocal<Random>(() => new Random(GetUniqueSeed()));

    public static int Next() 
    { 
        return _rng.Value.Next(); 
    } 

    private const long SeedFactor = 1181783497276652981L;
    private static long _seed = 8682522807148012L;

    public static int GetUniqueSeed()
    {
        long next, current;
        do
        {
            current = Interlocked.Read(ref _seed);
            next = current * SeedFactor;
        } while (Interlocked.CompareExchange(ref _seed, next, current) != current);
        return (int)next ^ Environment.TickCount;
   } 
}
捎一片雪花 2025-02-01 01:34:35

不,使用来自多个线程的同一实例会导致其破裂并返回所有0。但是,创建线程安全版本(无需在每个调用next())的无需讨厌的锁。改编自本文

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

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

        return _local.Next();
    }
}

这个想法是为每个线程保留一个单独的static Random变量。但是,以明显的方式执行此操作会失败,因为Random的另一个问题 - 如果在几乎同一时间创建了多个实例(在约15ms之内),它们将全部返回相同的值!为了解决此问题,我们创建一个全球静态随机实例,以生成每个线程使用的种子。

顺便说一句,上面的文章具有随机的这两个问题的代码。

No, using the same instance from multiple threads can cause it to break and return all 0's. However, creating a thread-safe version (without needing nasty locks on every call to Next()) is simple. Adapted from the idea in this article:

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

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

        return _local.Next();
    }
}

The idea is to keep a separate static Random variable for each thread. Doing that in the obvious way fails, however, because of another issue with Random - if multiple instances are created at nearly the same time (within about 15ms), they will all return the same values! To fix this, we create a globally-static Random instance to generate the seeds used by each thread.

The above article, by the way, has code demonstrating both of these issues with Random.

毁虫ゝ 2025-02-01 01:34:35

下一个方法可以实现线程安全性。但是,这是一种实例方法。如果您不在不同线程上共享随机的实例,则不必担心一个实例中的状态腐败。请勿在不同的线程上使用随机的单个实例,而不会持有某种独有的锁定。

乔恩·斯基特(Jon Skeet)在此主题上有几个不错的帖子:

staticrandom staticrandom 一个>
重新审视随机性

正如某些评论员所指出的使用随机的不同实例,这些实例是线程排名,但被播种相同,因此会诱导伪数字的相同序列,因为它们可以同时或在彼此之间紧密的时间近处创建。减轻该问题的一种方法是使用主随机实例(由单个线程锁定)来生成一些随机种子并初始化新的随机>随机其他每个线程的实例使用。

There's nothing special done in the Next method to achieve thread safety. However, it's an instance method. If you don't share instances of Random across different threads, you don't have to worry about state corruption within an instance. Do not use a single instance of Random across different threads without holding an exclusive lock of some sort.

Jon Skeet has a couple nice posts on this subject:

StaticRandom
Revisiting randomness

As noted by some commentators, there is another potential problem in using different instances of Random that are thread-exclusive, but are seeded identically, and therefore induce the identical sequences of pseudorandom numbers, because they may be created at the same time or within close temporal proximity of each other. One way to alleviate that issue is to use a master Random instance (which is locked by a single thread) to generate some random seeds and initialize new Random instances for every other thread to use.

oО清风挽发oО 2025-02-01 01:34:35

微软的官方答案是非常 strong no 。来自 http://msdn.microsoft.com/en-en-us/en-en-us/ library/system.random.aspx#8

随机对象不是线程安全的。如果您的应用程序从多个线程调用随机方法,则必须使用同步对象来确保只有一个线程可以一次访问随机数生成器。如果您不确保以线程安全的方式访问随机对象,请调用返回随机数返回0的方法。

如DOC中所述由多个线程使用:它只是停止工作。

(即,有一个种族条件,当触发时,从“ andural.next ....”的返回值对于所有后续调用的方法为0。)

The offical answer from Microsoft is a very strong no. From http://msdn.microsoft.com/en-us/library/system.random.aspx#8:

Random objects are not thread safe. If your app calls Random methods from multiple threads, you must use a synchronization object to ensure that only one thread can access the random number generator at a time. If you don't ensure that the Random object is accessed in a thread-safe way, calls to methods that return random numbers return 0.

As described in the docs, there is a very nasty side effect that can happen when the same Random object is used by multiple threads: it just stops working.

(i.e. there is a race condition which when triggered, the return value from the 'random.Next....' methods will be 0 for all subsequent calls.)

扬花落满肩 2025-02-01 01:34:35

C#的Random.next()方法线程安全?

如前所述,Anwer是 no 。但是,从 .net6 开始,我们有盒子线程安全替代方案:randy.shared.next();

请参阅此处的详细信息

Is C#'s Random.Next() method thread safe?

As was written before, anwer is No. However, starting from .NET6, we have out of box thread-safe alternative: Random.Shared.Next();

See details here.

一桥轻雨一伞开 2025-02-01 01:34:35

不,这不是线程的安全。如果您需要使用不同线程的相同实例,则必须同步使用情况。

不过,我真的看不到您需要的原因。每个线程具有自己的随机类实例将更加有效。

No, it's not thread safe. If you need to use the same instance from different threads, you have to synchronise the usage.

I can't really see any reason why you would need that, though. It would be more efficient for each thread to have their own instance of the Random class.

酒与心事 2025-02-01 01:34:35

另一种安全方法是使用threadlocal&lt; t&gt;如下:

new ThreadLocal<Random>(() => new Random(GenerateSeed()));

generateSeed()方法将需要每次调用唯一值以确保随机返回一个唯一值每个线程中的数字序列都是唯一的。

static int SeedCount = 0;
static int GenerateSeed() { 
    return (int) ((DateTime.Now.Ticks << 4) + 
                   (Interlocked.Increment(ref SeedCount))); 
}

将适用于少量线程。

Another thread safe way is to use ThreadLocal<T> as follows:

new ThreadLocal<Random>(() => new Random(GenerateSeed()));

The GenerateSeed() method will need to return a unique value each time it is called to assure that the random number sequences are unique in each thread.

static int SeedCount = 0;
static int GenerateSeed() { 
    return (int) ((DateTime.Now.Ticks << 4) + 
                   (Interlocked.Increment(ref SeedCount))); 
}

Will work for small numbers of threads.

瑶笙 2025-02-01 01:34:35

更新从.net 6 在窗帘后面进行同步)。

使用threadlocal

public static class ThreadSafeRandom
{
    private static readonly System.Random GlobalRandom = new Random();
    private static readonly ThreadLocal<Random> LocalRandom = new ThreadLocal<Random>(() => 
    {
        lock (GlobalRandom)
        {
            return new Random(GlobalRandom.Next());
        }
    });

    public static int Next(int min = 0, int max = Int32.MaxValue)
    {
        return LocalRandom.Value.Next(min, max);
    }
}

Update Starting from .NET 6 Random.Shared provides a built-in thread-safe Random type (using ThreadStatic behind the curtains for synchronization) .

Original Answer Reimplementation of BlueRaja's answer using ThreadLocal:

public static class ThreadSafeRandom
{
    private static readonly System.Random GlobalRandom = new Random();
    private static readonly ThreadLocal<Random> LocalRandom = new ThreadLocal<Random>(() => 
    {
        lock (GlobalRandom)
        {
            return new Random(GlobalRandom.Next());
        }
    });

    public static int Next(int min = 0, int max = Int32.MaxValue)
    {
        return LocalRandom.Value.Next(min, max);
    }
}
遗忘曾经 2025-02-01 01:34:35

就其价值而言,这里是继承Random的线程安全性强的RNG。

该实现包括静态输入点,易于使用,它们的名称与公共实例方法相同,但前缀为“ get”。

调用rngcryptoserviceprovider.getbytes是一个相对昂贵的操作。通过使用内部缓冲区或“池”来减少这种方法,以使rngcryptoserviceprovider更有效地使用频率。如果应用程序域中几代人几代,则可以将其视为开销。

using System;
using System.Security.Cryptography;

public class SafeRandom : Random
{
    private const int PoolSize = 2048;

    private static readonly Lazy<RandomNumberGenerator> Rng =
        new Lazy<RandomNumberGenerator>(() => new RNGCryptoServiceProvider());

    private static readonly Lazy<object> PositionLock =
        new Lazy<object>(() => new object());

    private static readonly Lazy<byte[]> Pool =
        new Lazy<byte[]>(() => GeneratePool(new byte[PoolSize]));

    private static int bufferPosition;

    public static int GetNext()
    {
        while (true)
        {
            var result = (int)(GetRandomUInt32() & int.MaxValue);

            if (result != int.MaxValue)
            {
                return result;
            }
        }
    }

    public static int GetNext(int maxValue)
    {
        if (maxValue < 1)
        {
            throw new ArgumentException(
                "Must be greater than zero.",
                "maxValue");
        }
        return GetNext(0, maxValue);
    }

    public static int GetNext(int minValue, int maxValue)
    {
        const long Max = 1 + (long)uint.MaxValue;

        if (minValue >= maxValue)
        {
            throw new ArgumentException(
                "minValue is greater than or equal to maxValue");
        }

        long diff = maxValue - minValue;
        var limit = Max - (Max % diff);

        while (true)
        {
            var rand = GetRandomUInt32();
            if (rand < limit)
            {
                return (int)(minValue + (rand % diff));
            }
        }
    }

    public static void GetNextBytes(byte[] buffer)
    {
        if (buffer == null)
        {
            throw new ArgumentNullException("buffer");
        }

        if (buffer.Length < PoolSize)
        {
            lock (PositionLock.Value)
            {
                if ((PoolSize - bufferPosition) < buffer.Length)
                {
                    GeneratePool(Pool.Value);
                }

                Buffer.BlockCopy(
                    Pool.Value,
                    bufferPosition,
                    buffer,
                    0,
                    buffer.Length);
                bufferPosition += buffer.Length;
            }
        }
        else
        {
            Rng.Value.GetBytes(buffer);
        }
    }

    public static double GetNextDouble()
    {
        return GetRandomUInt32() / (1.0 + uint.MaxValue);
    }

    public override int Next()
    {
        return GetNext();
    }

    public override int Next(int maxValue)
    {
        return GetNext(0, maxValue);
    }

    public override int Next(int minValue, int maxValue)
    {
        return GetNext(minValue, maxValue);
    }

    public override void NextBytes(byte[] buffer)
    {
        GetNextBytes(buffer);
    }

    public override double NextDouble()
    {
        return GetNextDouble();
    }

    private static byte[] GeneratePool(byte[] buffer)
    {
        bufferPosition = 0;
        Rng.Value.GetBytes(buffer);
        return buffer;
    }

    private static uint GetRandomUInt32()
    {
        uint result;
        lock (PositionLock.Value)
        {
            if ((PoolSize - bufferPosition) < sizeof(uint))
            {
                GeneratePool(Pool.Value)
            }

            result = BitConverter.ToUInt32(
                Pool.Value,
                bufferPosition);
            bufferPosition+= sizeof(uint);
        }

        return result;
    }
}

For what its worth, here is a thread-safe, cryptographically strong RNG that inherits Random.

The implementation includes static entry points for ease of use, they have the same names as the public instance methods but are prefixed with "Get".

A call to the RNGCryptoServiceProvider.GetBytes is a relatively expensive operation. This is mitigated through the use of an internal buffer or "Pool" to make less frequent, and more efficient use of RNGCryptoServiceProvider. If there are few generations in an application domain then this could be viewed as overhead.

using System;
using System.Security.Cryptography;

public class SafeRandom : Random
{
    private const int PoolSize = 2048;

    private static readonly Lazy<RandomNumberGenerator> Rng =
        new Lazy<RandomNumberGenerator>(() => new RNGCryptoServiceProvider());

    private static readonly Lazy<object> PositionLock =
        new Lazy<object>(() => new object());

    private static readonly Lazy<byte[]> Pool =
        new Lazy<byte[]>(() => GeneratePool(new byte[PoolSize]));

    private static int bufferPosition;

    public static int GetNext()
    {
        while (true)
        {
            var result = (int)(GetRandomUInt32() & int.MaxValue);

            if (result != int.MaxValue)
            {
                return result;
            }
        }
    }

    public static int GetNext(int maxValue)
    {
        if (maxValue < 1)
        {
            throw new ArgumentException(
                "Must be greater than zero.",
                "maxValue");
        }
        return GetNext(0, maxValue);
    }

    public static int GetNext(int minValue, int maxValue)
    {
        const long Max = 1 + (long)uint.MaxValue;

        if (minValue >= maxValue)
        {
            throw new ArgumentException(
                "minValue is greater than or equal to maxValue");
        }

        long diff = maxValue - minValue;
        var limit = Max - (Max % diff);

        while (true)
        {
            var rand = GetRandomUInt32();
            if (rand < limit)
            {
                return (int)(minValue + (rand % diff));
            }
        }
    }

    public static void GetNextBytes(byte[] buffer)
    {
        if (buffer == null)
        {
            throw new ArgumentNullException("buffer");
        }

        if (buffer.Length < PoolSize)
        {
            lock (PositionLock.Value)
            {
                if ((PoolSize - bufferPosition) < buffer.Length)
                {
                    GeneratePool(Pool.Value);
                }

                Buffer.BlockCopy(
                    Pool.Value,
                    bufferPosition,
                    buffer,
                    0,
                    buffer.Length);
                bufferPosition += buffer.Length;
            }
        }
        else
        {
            Rng.Value.GetBytes(buffer);
        }
    }

    public static double GetNextDouble()
    {
        return GetRandomUInt32() / (1.0 + uint.MaxValue);
    }

    public override int Next()
    {
        return GetNext();
    }

    public override int Next(int maxValue)
    {
        return GetNext(0, maxValue);
    }

    public override int Next(int minValue, int maxValue)
    {
        return GetNext(minValue, maxValue);
    }

    public override void NextBytes(byte[] buffer)
    {
        GetNextBytes(buffer);
    }

    public override double NextDouble()
    {
        return GetNextDouble();
    }

    private static byte[] GeneratePool(byte[] buffer)
    {
        bufferPosition = 0;
        Rng.Value.GetBytes(buffer);
        return buffer;
    }

    private static uint GetRandomUInt32()
    {
        uint result;
        lock (PositionLock.Value)
        {
            if ((PoolSize - bufferPosition) < sizeof(uint))
            {
                GeneratePool(Pool.Value)
            }

            result = BitConverter.ToUInt32(
                Pool.Value,
                bufferPosition);
            bufferPosition+= sizeof(uint);
        }

        return result;
    }
}
握住你手 2025-02-01 01:34:35

由于随机不是线程安全,因此您应该每个线程一个,而不是全局实例。如果您担心这些多个随机同时播种的类(即dateTime.now.ticks之类的),则可以使用guid < /code> s播种每个。 .NET GUID生成器的长度相当长以确保不可重复的结果,因此:

var rnd = new Random(BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0))

Since Random isn't thread-safe, you should have one per thread, rather than a global instance. If you're worried about these multiple Random classes being seeded at the same time (i.e. by DateTime.Now.Ticks or such), you can use Guids to seed each of them. The .NET Guid generator goes to considerable lengths to ensure non-repeatable results, hence:

var rnd = new Random(BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0))
逆夏时光 2025-02-01 01:34:35

每个文档

这种类型的任何公共静态(在Visual Basic中共享)都是线程安全的。任何实例成员都不能保证是线程安全的。

http://msdn.microsoft.com/en-en-us/library/ system.random.aspx

Per documentation

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

http://msdn.microsoft.com/en-us/library/system.random.aspx

楠木可依 2025-02-01 01:34:35

这是一个简单的解决方案,不涉及创建类。隐藏了临时Lambda中的所有内容:

private static Func<int, int, int> GetRandomFunc()
{
    Random random = new Random();
    object lockObject = new object();

    return (min, max) =>
    {
        lock (lockObject)
        {
            return random.Next(min, max);
        }
    };
}

在需要线程安全的随机生成器定义的任何类中

private static readonly Func<int, int, int> GetRandomNext = GetRandomFunc();

,然后在类中自由使用:

int nextRandomValue = GetRandomNext(0, 10);

Radndom函数可以根据所需的内容具有不同的签名。例如

private static Func<int> GetRandomFunc()
{
    Random random = new Random();
    object lockObject = new object();

    return () =>
    {
        lock (lockObject)
        {
            return random.Next();
        }
    };
}

Here is a simple solution that doesn't involve creating classes. Hides everything inside an ad-hoc lambda:

private static Func<int, int, int> GetRandomFunc()
{
    Random random = new Random();
    object lockObject = new object();

    return (min, max) =>
    {
        lock (lockObject)
        {
            return random.Next(min, max);
        }
    };
}

In any class that needs a thread safe random generator define

private static readonly Func<int, int, int> GetRandomNext = GetRandomFunc();

Then use it freely inside your class:

int nextRandomValue = GetRandomNext(0, 10);

The radndom function can have different signatures depending what is needed. e.g.

private static Func<int> GetRandomFunc()
{
    Random random = new Random();
    object lockObject = new object();

    return () =>
    {
        lock (lockObject)
        {
            return random.Next();
        }
    };
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文