TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #2972 2.39K
День 2471. #ЗаметкиНаПолях
Вы Всё Ещё Используете new Random()? Окончание

Начало

Проблема с Random в .NET Framework
Основных проблем с Random в .NET Framework две:
1. При вызове new Random() в .NET Framework он использует системные часы для посева;
2. Системные часы имеют конечное разрешение.
Т.е. при быстром последовательном вызове new Random() в .NET Framework могут возникнуть два экземпляра Random с одинаковым начальным значением, что означает, что экземпляры Random вернут идентичную последовательность чисел:
// <TargetFramework>net48</TargetFramework>
Parallel.For(0, 10, x =>
{
Random rnd = new();
var value = rnd.Next();
Console.WriteLine(value);
});

При выполнении этого кода несколько чисел (а то и все) могут быть одинаковыми, а это не то, чего мы хотим.

Решение
Создать один экземпляр Random, который используется исключительно для предоставления начальных значений для остальных экземпляров Random. Поскольку начальные значения случайны, экземпляры Random не коррелируют, и вы можете полностью избежать описанной выше проблемы. Этот подход к инициализации используется по умолчанию в .NET Core, поэтому проблема возникает только в .NET Framework.

Мы можем реализовать тот же подход в классе-обёртке ThreadSafeRandom, показанном ниже. Этот класс использует [ThreadStatic], избегая проблем с инициализацией в .NET Framework:
internal static class ThreadSafeRandom
{
[ThreadStatic]
private static Random? _local;
private static readonly
Random Global = new Random();

private static Random Instance
{
get
{
if (_local is null)
{
int seed;
// избегаем конкурентного доступа
lock (Global)
{
seed = Global.Next();
}

_local = new Random(seed);
}
return _local;
}
}

public static int Next() => Instance.Next();
}

Эту потокобезопасную реализацию, можно использовать во всех версиях фреймворка:
Parallel.For(0, 10, x =>
{
var value = ThreadSafeRandom.Next();
Console.WriteLine(value);
});


Если вы используете .NET6+, рекомендуется использовать встроенный Random.Shared. В более ранних версиях вы можете использовать приведённый выше ThreadSafeRandom для решения этих проблем. Если вы ориентируетесь как на .NET6+, так и на .NET Framework, можно использовать директивы #if для разделения реализации в зависимости от целевой среды.

Источник: https://andrewlock.net/building-a-thread-safe-random-implementation-for-dotnet-framework/
  • 👍 13
More from @netdeveloperdiary
  1. Sep 30, 2026Post #3356
  2. Sep 29, 2026Фото 3 (с) Анатолий Кулаков
  3. Sep 29, 2026День 2799. Конференция DotNext 2026. Часть 1 25 и 26 сентября в Москве прошла очередная ко…
  4. Sep 28, 2026День 2798. #Оффтоп Утиная Типизация в C# с Помощью Перехватчиков. Часть 2 Некоторое время…
  5. Sep 27, 2026День 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продол…
  6. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →