Каждый раз, когда вы делаете new Random()
, он инициализируется с помощью часов. Это означает, что в тесном цикле вы получаете одно и то же значение много раз. Вы должны хранить один Random
экземпляр и продолжать использовать Next
на том же экземпляре.
//Function to get a random number
private static readonly Random random = new Random();
private static readonly object syncLock = new object();
public static int RandomNumber(int min, int max)
{
lock(syncLock) { // synchronize
return random.Next(min, max);
}
}
Редактировать (см. Комментарии): зачем нам lock
здесь?
По сути, Next
собирается изменить внутреннее состояние экземпляра Random
. Если мы сделаем это одновременно из нескольких потоков, вы могли бы утверждать, что "мы только что сделали результат еще более случайным", но то, что мы на самом деле делаем, потенциально может сломать внутренняя реализация, и мы могли бы также начать получать одинаковые числа из разных потоков, что может быть проблемой, а может и не быть. Гарантия того, что происходит внутри, является более важной проблемой; поскольку Random
не не дает какие-либо гарантии безопасности потоков. Таким образом, есть два допустимых подхода:
- синхронизировать, чтобы мы не обращались к нему одновременно из разных потоков
- использовать разные
Random
экземпляров на поток
Либо может быть в порядке; но мьютексирование единственного экземпляра от нескольких вызывающих одновременно одновременно просто вызывает проблемы.
lock
достигает первого (и более простого) из этих подходов; Тем не менее, другой подход может быть:
private static readonly ThreadLocal<Random> appRandom
= new ThreadLocal<Random>(() => new Random());
это тогда для каждого потока, поэтому вам не нужно синхронизировать.