Вставка рандомного текста. C#.

indigorav

Client
Регистрация
20.10.2018
Сообщения
25
Благодарностей
2
Баллы
3
Всем привет! Прошу помочь разобраться)

Пишу на C# шаблон. Сейчас стоит задача: Есть поле ввода, туда нужно будет вставлять комментарий, всегда разные. Вот не могу решить как это реализовать.
если пишу на C#, то можно ли это реализовать только кодом? или нужно будет применять стандартные методы зеннопостера?
Обычно ищу сам, и знаю что можно отыскать и решить, только вот прошу вас помочь немножко это скомпанавать, или может кто то как раз это недавно делал и поможет.
В общем повторюсь - Есть поле, куда я буду вписывать комменты. Под разными видео - разные комменты.
Как будет сделан текст: в разных файлах или со спинтаксом в одном файле, или еще как то - я пока не разобрался, каша уже в голове))) Помогите хотя бы планом) В общем, кто сможет помочь, знает как помочь, это я знаю. Спасибо!
 

RoyalBank

Client
Регистрация
07.09.2015
Сообщения
557
Благодарностей
547
Баллы
93
Если фразы будут в списке/файле, то можешь брать случайную строку из списка.
C#:
lst[Global.Classes.rnd.Next(0,lst.Count)]
Если всегда необходима уникальная строка, то удаляй ее после взятия. Если не хочешь удалять, то можешь добавлять к строке разделитель "|" с 0 или 1. Затем при взятии сплитить и проверять значение, если использовал, то просто обновляешь строку в списке/файле..
 
  • Спасибо
Реакции: indigorav

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
Если фразы будут в списке/файле, то можешь брать случайную строку из списка.
C#:
lst[Global.Classes.rnd.Next(0,lst.Count)]
Если всегда необходима уникальная строка, то удаляй ее после взятия. Если не хочешь удалять, то можешь добавлять к строке разделитель "|" с 0 или 1. Затем при взятии сплитить и проверять значение, если использовал, то просто обновляешь строку в списке/файле..
Рекомендую никогда не использовать такой рандом Global.Classes.rnd.Next(0,10);
Дело в том, что данный рандом в Зеннопостере работает не корректно в многопоточном режиме и спустя определенное количество итераций у нас получается так, что рандом возвращает всегда значение 0.

Чтобы это проверить/доказать - можно использовать например код:
Код:
// Внимание! Из-за количества итераций и времени на вывод уведомление в лог - отрабатывать будет более 10 минут
string[] clips = new string[] { "1.mp3", "2.mp3", "3.mp3", "4.mp3"};
System.Threading.Tasks.Parallel.For(0, 10000000, (i) =>
{
var clipIndex = Global.Classes.rnd.Next(4);
var clip = clips[clipIndex];
  project.SendInfoToLog(string.Format(@"{0} {1}",clip, clipIndex));
});
Самое интересное, что даже ниже приведённый код не решает эту проблему:
Код:
Random rnd = new Random();
string[] clips = new string[] { "1.mp3", "2.mp3", "3.mp3", "4.mp3"};
System.Threading.Tasks.Parallel.For(0, 10000000, (i) =>
{
var clipIndex = rnd.Next(4);
var clip = clips[clipIndex];
  project.SendInfoToLog(string.Format(@"{0} {1}",clip, clipIndex));
});
Результат выполнения видим в логе на стриншоте:
код.jpg

Данная проблема с предпочтительным решение описана в книге ISBN 9781617292996 (исходник примера: Безопасный Рандом ).
Собственно после обнаружения этой проблемы - в своих шаблонах всегда включаю данное решение (простите, за 5 копеек, но подумал что это будет полезным для Вас).
 

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 379
Благодарностей
2 039
Баллы
113
всегда он работал норм
 

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 379
Благодарностей
2 039
Баллы
113
ты запускаешь в паралели и хотитшь разное, думай что запускаешь
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
ты запускаешь в паралели и хотитшь разное, думай что запускаешь
Я понимаю, что тебе скучно, дорогой мой друг - делать нечего, уже всё автоматизировал, сидишь и всех троллишь.
Но, видишь, дело тут такое, что с нервами у меня полный порядок и отвечать на твои подколы здесь и в каких либо других темах я не вижу смысла.
В этом конкретном случае я лишь оставлю готовое решение для тех, кому сложно разобраться самостоятельно - а кому не нравится - может не читать и не обращать внимания на мои сообщения.

В общий код вставляем:
Код:
#region Потокобезопасный генератор случайных чисел
     public sealed class GoodRandom : Random {
       private static int seed() { return Guid.NewGuid().ToString().GetHashCode(); }
         private ThreadLocal<Random> rand = new ThreadLocal<Random>(() => new Random(seed()));
 
         public override int Next() { return rand.Value.Next(); }
         public override int Next(int maxValue) { return rand.Value.Next(maxValue); }
         public override int Next(int minValue, int maxValue) { return rand.Value.Next(minValue, maxValue); }
         public override double NextDouble() { return rand.Value.NextDouble(); }
         public override void NextBytes(byte[] buffer) { rand.Value.NextBytes(buffer); }        
    }
  #endregion
И тогда код начинает работать так, как мы ожидаем вне зависимости от многопоточности и количества итераций:
Код:
GoodRandom rnd = new GoodRandom(); // здесь мы уже будем использовать потокобезопасный рандом
string[] clips = new string[] { "1.mp3", "2.mp3", "3.mp3", "4.mp3"};
System.Threading.Tasks.Parallel.For(0, 10000000, (i) =>
{
var clipIndex = rnd.Next(4);
var clip = clips[clipIndex];
  project.SendInfoToLog(string.Format(@"{0} {1}",clip, clipIndex));
});
Именно такое решение я сейчас всегда переношу из одного проекта в другой и Вам точно также советую (или ждём пока Зеннолаб запилит потокобезопасный рандом в Зеннопостер чтобы он был таким с "коробки").
 

indigorav

Client
Регистрация
20.10.2018
Сообщения
25
Благодарностей
2
Баллы
3

RoyalBank

Client
Регистрация
07.09.2015
Сообщения
557
Благодарностей
547
Баллы
93
простите, за 5 копеек, но подумал что это будет полезным для Вас
Это очень крутые 5 копеек, и будут полезны не только мне :-) Я о такой проблеме никогда не слышал.
Спасибо, за полезную информацию и адаптированную версию кода!
 
  • Спасибо
Реакции: BAZAg

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 689
Баллы
113
вот честно, не понял в коде ни фига.... :-)
однако псевдо случайность однажды меня подвела, выдавала одну и туже последовательность . так как мне надо было получить всего несколько разных чисел я воспользовался системным временем для генерации нового сида, а что бы новая последовательность была уникальной , сделал паузу в 1 тик. я у себя так получаю случайные числа.
C#:
        public static int rnd_my (int start=0, int end=100 ) {
            Thread.Sleep(1);
            int seed = (int) DateTime.Now.Ticks & 0x0000FFFF;  // новый уникальный сид
            Random rnd = new Random(seed); // новый уникальный рандом
            return rnd.Next(start, end);
           }
что бы без задержек генерировать новый уникальный рандом, надо найти какие то другие правила для сида, тогда можно убрать паузу и будет летать :-)
возможно вот этот код может генерить новый сид без задержки
Guid.NewGuid().ToString().GetHashCode();
но я не проверял :-)
 
  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
вот честно, не понял в коде ни фига.... :-)
однако псевдо случайность однажды меня подвела, выдавала одну и туже последовательность . так как мне надо было получить всего несколько разных чисел я воспользовался системным временем для генерации нового сида, а что бы новая последовательность была уникальной , сделал паузу в 1 тик. я у себя так получаю случайные числа.
C#:
        public static int rnd_my (int start=0, int end=100 ) {
            Thread.Sleep(1);
            int seed = (int) DateTime.Now.Ticks & 0x0000FFFF;  // новый уникальный сид
            Random rnd = new Random(seed); // новый уникальный рандом
            return rnd.Next(start, end);
           }
что бы без задержек генерировать новый уникальный рандом, надо найти какие то другие правила для сида, тогда можно убрать паузу и будет летать :-)
возможно вот этот код может генерить новый сид без задержки
Guid.NewGuid().ToString().GetHashCode();
но я не проверял :-)
Я раньше точно также решал эту проблему. Но, в один день у меня появилась задача по генерации тегов на html страничках с чётким лимитом времени 5000 страничек в секунду. И тут оказалось, что если идти таким способом - то мне никак не получилось бы предоставить такое готовое решение. Правда в своем решении я потом ещё вместо списков использовал конкурентные коллекции, но это уже выходит за пределы данного обсуждения.

Цитирую Глава 13.5 (ISBN 9781617292996) - чтобы кто-то кто решит разбираться с этим смог прочитать первоисточник.
Часто при работе с многопоточным кодом нужно генерировать случайные числа для той или иной операции в программе. Например, предположим, что вы пишете приложение веб-сервера, который в ответ на запрос пользователя должен отправлять
случайный аудиоклип. По соображениям производительности набор аудиоклипов загружен в память сервера, конкурентно получающего большое количество запросов.
При каждом запросе аудиоклип должен выбираться случайным образом и отправляться пользователю для воспроизведения. В большинстве случаев класс System.Random является достаточно быстрым решением для получения случайных числовых значений. Но эффективное применение экземпляра Random, к которому осуществляется параллельный доступ в высокопроизводительных решениях, становится сложной проблемой. Когда экземпляр класса Random задействуется несколькими потоками, его внутреннее состояние может быть нарушено и он всегда будет возвращать ноль.
Решение: использование объекта ThreadLocal. ThreadLocal<T> гарантирует, что каждый поток получит собственный экземпляр класса Random, и, следовательно, обеспечивает потокобезопасный доступ даже в многопоточной программе.
В листинге 13.7 показана реализация потокобезопасного генератора случайных чисел с использованием класса ThreadLocal<T>, который предоставляет строго типизированный и локально ограниченный тип для создания экземпляров объектов, хранящихся отдельно для каждого потока.
листинг.jpg

ThreadSafeRandom — потокобезопасный генератор псевдослучайных чисел.
Этот класс является подклассом Random и переопределяет методы Next, NextDouble и NextBytes. Метод MakeRandomSeed предоставляет уникальное значение для каждого экземпляра базового класса Random, которое не зависит от системных часов.
Конструктор ThreadLocal<T> принимает делегата Func<T> для создания локального для потока экземпляра класса Random. ThreadLocal<T>.Value используется для доступа к базовому значению. Здесь мы получаем доступ к экземпляру ThreadSafeRandom из параллельного цикла, чтобы имитировать конкурентную среду. В этом примере параллельный цикл конкурентно вызывает ThreadSafeRandom, чтобы получить случайное число для доступа к массиву clips:
листинг2.jpg

Один экземпляр ThreadLocal<T> занимает в памяти несколько сотен байт, поэтому важно учитывать, сколько таких активных экземпляров необходимо в каждый момент. Если программе требуется много параллельных операций, то рекомендуется работать с локальной копией, чтобы как можно реже обращаться к локальному хранилищу потока.
 

DevOps

Client
Регистрация
30.11.2020
Сообщения
495
Благодарностей
311
Баллы
63
Я раньше точно также решал эту проблему. Но, в один день у меня появилась задача по генерации тегов на html страничках с чётким лимитом времени 5000 страничек в секунду. И тут оказалось, что если идти таким способом - то мне никак не получилось бы предоставить такое готовое решение. Правда в своем решении я потом ещё вместо списков использовал конкурентные коллекции, но это уже выходит за пределы данного обсуждения.

Цитирую Глава 13.5 (ISBN 9781617292996) - чтобы кто-то кто решит разбираться с этим смог прочитать первоисточник.
Часто при работе с многопоточным кодом нужно генерировать случайные числа для той или иной операции в программе. Например, предположим, что вы пишете приложение веб-сервера, который в ответ на запрос пользователя должен отправлять
случайный аудиоклип. По соображениям производительности набор аудиоклипов загружен в память сервера, конкурентно получающего большое количество запросов.
При каждом запросе аудиоклип должен выбираться случайным образом и отправляться пользователю для воспроизведения. В большинстве случаев класс System.Random является достаточно быстрым решением для получения случайных числовых значений. Но эффективное применение экземпляра Random, к которому осуществляется параллельный доступ в высокопроизводительных решениях, становится сложной проблемой. Когда экземпляр класса Random задействуется несколькими потоками, его внутреннее состояние может быть нарушено и он всегда будет возвращать ноль.
Решение: использование объекта ThreadLocal. ThreadLocal<T> гарантирует, что каждый поток получит собственный экземпляр класса Random, и, следовательно, обеспечивает потокобезопасный доступ даже в многопоточной программе.
В листинге 13.7 показана реализация потокобезопасного генератора случайных чисел с использованием класса ThreadLocal<T>, который предоставляет строго типизированный и локально ограниченный тип для создания экземпляров объектов, хранящихся отдельно для каждого потока.
Посмотреть вложение 51036
ThreadSafeRandom — потокобезопасный генератор псевдослучайных чисел.
Этот класс является подклассом Random и переопределяет методы Next, NextDouble и NextBytes. Метод MakeRandomSeed предоставляет уникальное значение для каждого экземпляра базового класса Random, которое не зависит от системных часов.
Конструктор ThreadLocal<T> принимает делегата Func<T> для создания локального для потока экземпляра класса Random. ThreadLocal<T>.Value используется для доступа к базовому значению. Здесь мы получаем доступ к экземпляру ThreadSafeRandom из параллельного цикла, чтобы имитировать конкурентную среду. В этом примере параллельный цикл конкурентно вызывает ThreadSafeRandom, чтобы получить случайное число для доступа к массиву clips:
Посмотреть вложение 51037
Один экземпляр ThreadLocal<T> занимает в памяти несколько сотен байт, поэтому важно учитывать, сколько таких активных экземпляров необходимо в каждый момент. Если программе требуется много параллельных операций, то рекомендуется работать с локальной копией, чтобы как можно реже обращаться к локальному хранилищу потока.
Да уж, чем дальше в лес тем толще партизаны.
Придется в очередной раз править свой первый учебный шаблон
PS Подскажите, можно ли решать это таким образом - в коде будет находиться залоченый кусок кода с генератором который для потока будет создавать рандомное значение и передавать по назначению в данном потоке. Могу ли я предположить что таким образом, после разлока и обращению следующего потока к данному участку кода будет вновь генерироваться новое значение?
Не будет ли пересечений рандомных значений в потоках если у каждого потока для указанного рандомного значения существует собственная переменная?
 
Последнее редактирование:
  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
Да уж, чем дальше в лес тем толще партизаны.
Придется в очередной раз править свой первый учебный шаблон
Если экземпляр Random rnd = new Random(); создается в каждом отдельном потоке Зеннопостера, и там же используется (без каких-либо System.Threading.Tasks.Parallel.For - если в них нужен рандом - внутри них и создается экземпляр)- проблемы нет.
Проблема есть, когда пытаться дёргать Global.Classes.rnd.Next()

Но, проблема может вылезти в том, что допустим, мы запустили шаблон в 100 потоков. Был создан одновременной экземпляр Random rnd = new Random(); во всех потоках. По-умолчанию он использует время в качестве seed - и вуаля - в каждом потоке каждый вызов rnd.Next() может начать выдавать одинаковую последовательность (при одинаковом seed ряд псевдослучайных чисел будет одинаковым, для примера создайте экземпляр с значением например 1 и попробуйте вызвать 10 раз рандом с выводом в лог).

Выше по тексту есть сообщение - просто добавляете в общий код класс, и вызываете рандом не Random rnd = new Random();, а GoodRandom rnd = new GoodRandom(); и о том, что что-то там в объекте рандома может сломаться, или например что два разных потока вдруг начали выдавать одинаковые последовательности - можно забыть.

PS Подскажите, можно ли решать это таким образом - в коде будет находиться залоченый кусок кода с генератором который для потока будет создавать рандомное значение и передавать по назначению в данном потоке. Могу ли я предположить что таким образом, после разлока и обращению следующего потока к данному участку кода будет вновь генерироваться новое значение?
Не будет ли пересечений рандомных значений в потоках если у каждого потока для указанного рандомного значения существует собственная переменная?
Можно конечно.
Но зачем использовать локи там, где без них можно обойтись?

P.S. Также с момента моего сообщения прошло больше года - может быть в Зеннопостер уже внедрен потокобезопасный рандом (я не следил за историей изменений версий Зенно).
 
Последнее редактирование:
  • Спасибо
Реакции: DevOps

DevOps

Client
Регистрация
30.11.2020
Сообщения
495
Благодарностей
311
Баллы
63
Если экземпляр Random rnd = new Random(); создается в каждом отдельном потоке Зеннопостера, и там же используется (без каких-либо System.Threading.Tasks.Parallel.For - если в них нужен рандом - внутри них и создается экземпляр)- проблемы нет.
Проблема есть, когда пытаться дёргать Global.Classes.rnd.Next()

Но, проблема может вылезти в том, что допустим, мы запустили шаблон в 100 потоков. Был создан одновременной экземпляр Random rnd = new Random(); во всех потоках. По-умолчанию он использует время в качестве seed - и вуаля - в каждом потоке каждый вызов rnd.Next() может начать выдавать одинаковую последовательность (при одинаковом seed ряд псевдослучайных чисел будет одинаковым, для примера создайте экземпляр с значением например 1 и попробуйте вызвать 10 раз рандом с выводом в лог).

Выше по тексту есть сообщение - просто добавляете в общий код класс, и вызываете рандом не Random rnd = new Random();, а GoodRandom rnd = new GoodRandom(); и о том, что что-то там в объекте рандома может сломаться, или например что два разных потока вдруг начали выдавать одинаковые последовательности - можно забыть.


Можно конечно.
Но зачем использовать локи там, где без них можно обойтись?

P.S> Также с момента моего сообщения прошло больше года - может быть в Зеннопостер уже внедрен потокобезопасный рандом (я не следил за историей изменений версий Зенно).
Потрясающе
" По-умолчанию он использует время в качестве seed - и вуаля - в каждом потоке каждый вызов rnd.Next() может начать выдавать одинаковую последовательность (при одинаковом seed ряд псевдослучайных чисел будет одинаковым"
Спасибо, это действительно очень важно при многопотоке.
Предполагаю что "время в качестве seed" внедрено во всех, требующих такой генерации, объектах, по умолчанию?
 
  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
Предполагаю что "время в качестве seed" внедрено во всех, требующих такой генерации, объектах, по умолчанию?
Если речь о случайных паузах, случайных строчках из списка и подобное - тут нужно спрашивать у разработчиков, как именно построены эти конструкции и являются ли они потокобезопасными и зависят ли они от времени (хотя да, банально если зависят - тогда несколько потоков могут обращаться к одной и той же случайной строке в списке - это было бы печально).
 

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 689
Баллы
113
Если речь о случайных паузах, случайных строчках из списка и подобное - тут нужно спрашивать у разработчиков, как именно построены эти конструкции и являются ли они потокобезопасными и зависят ли они от времени (хотя да, банально если зависят - тогда несколько потоков могут обращаться к одной и той же случайной строке в списке - это было бы печально).
эммм... как бы даже с идеальным рандомом, вероятность обращения к одной и той же строке по рандому не нулевая. вообще не корректный пример.
если не нужны пересечения в списках, то это не рандом, а лок надо использовать. ну или все вместе :ca:
 
  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
эммм... как бы даже с идеальным рандомом, вероятность обращения к одной и той же строке по рандому не нулевая. вообще не корректный пример.
если не нужны пересечения в списках, то это не рандом, а лок надо использовать. ну или все вместе :ca:
Я имел ввиду, что если к примеру мы стартанули 100 потоков, и попытались взять 100 случайных строчек из списка, в надежде получить 100 разных строчек, а в итоге получили в каждом потоке одну и ту же строчку...
 

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 689
Баллы
113
Я имел ввиду, что если к примеру мы стартанули 100 потоков, и попытались взять 100 случайных строчек из списка, в надежде получить 100 разных строчек, а в итоге получили в каждом потоке одну и ту же строчку...
ааа... ну да... понял :-)
 

Alexmd

Client
Регистрация
10.12.2018
Сообщения
1 021
Благодарностей
1 383
Баллы
113
@BAZAg
Захотелось покопаться, но, видимо, в новой 7.4.0.0 версии с рандомом уже порядок. По крайней мере, проблему с Вашего скрина не воспроизвести не удалось.
1623501133757.png
Тестировал этим кодом
C#:
// Внимание! Из-за количества итераций и времени на вывод уведомление в лог - отрабатывать будет более 10 минут
string[] clips = new string[] { "1.mp3", "2.mp3", "3.mp3", "4.mp3"};
System.Threading.Tasks.Parallel.For(0, 10000000, (i) => {
    var clipIndex = Global.Classes.rnd.Next(4);
    var clip = clips[clipIndex];
project.SendInfoToLog(string.Format(@"{0} {1}",clip, clipIndex)); });
 
  • Спасибо
Реакции: BAZAg и Ilshakin

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
видимо, в новой 7.4.0.0 версии с рандомом уже порядок. По крайней мере, проблему с Вашего скрина не воспроизвести не удалось.
Вывожу в лог только значения кратные 1000. Вариант с объектом Зенно:
78728


Вариант с объектом .Net
78729


Проблема в 5-й версии Зенно никуда не делась.
7-ю не использую - не представляю что там - не следил за историей изменений версий.
 
  • Спасибо
Реакции: Alexmd

Alexmd

Client
Регистрация
10.12.2018
Сообщения
1 021
Благодарностей
1 383
Баллы
113
Ну, на каждой 10000 итерации и в 7-ке показало дубли при той реализации.
Я отдаю себе отчет в том, что рандом - он всегда "псевдо" и не жду от него многого, какой бы алгоритм внутри его функции не был заложен.
Для того, чтобы получать рандомные элементы в каждой итерации, достаточно подсовывать рандому новую "точку отсчета" в этой каждой итерации.
Поэтому я давно так с ним и работаю. Мне достаточно в такой реализации лишь первой итерации функции рандома, что еще ни разу не подвело мои скромные требования.
1623503717287.png
Имею минимум кода, минимум головной боли и геморроя с разбирательствами, а главное, вполне ожидаемый результат.
C#:
// Внимание! Из-за количества итераций и времени на вывод уведомление в лог - отрабатывать будет более 10 минут
string[] clips = new string[] { "1.mp3", "2.mp3", "3.mp3", "4.mp3"};
System.Threading.Tasks.Parallel.For(0, 10000000, (i) =>
{
var clipIndex = new Random(Guid.NewGuid().ToString().GetHashCode()).Next(4);
var clip = clips[clipIndex];
  if(i % 10000 == 0)
      project.SendInfoToLog(string.Format(@"{0} - {1} {2}", i, clip, clipIndex));
});
 
  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
Для того, чтобы получать рандомные элементы в каждой итерации, достаточно подсовывать рандому новую "точку отсчета" в этой каждой итерации.
В предыдущем сообщении Вы показали код:
C#:
var clipIndex = Global.Classes.rnd.Next(4);
Как в этот код Вы будете подсовывать
рандому новую "точку отсчета"
?
Собственно, именно из-за использования Global.Classes.rnd я вообще ответил первый раз в этой теме - что при его вызове внутренняя структура объекта может быть нарушена что может повлиять на все потоки.

Вы, наверно видите разницу, что здесь Вы создаете объект, а в Global.Classes.rnd Вы используете уже созданный объект.
C#:
var clipIndex = new Random(Guid.NewGuid().ToString().GetHashCode()).Next(4);
В последнем коде, который Вы сбросили кроме var clipIndex = new Random(Guid.NewGuid().ToString().GetHashCode()).Next(4);, не менее важно, что экземпляр Рандом создается для каждого потока отдельно. Если бы он вызывался за пределами параллельного цикла - то на на какой-то итерации его структура могла быть нарушена и в результате любой вызов выдавал бы 0 (при чём заранее мы не знаем это будет первая или какая именно итерация), и самое главное, что мы никогда и не узнали бы об этой проблеме (ведь возвращается 0, а не ошибка )- мы бы думали что так и должно быть.


Ещё раз попытаюсь дополнить...
int clipIndex = new Random(Guid.NewGuid().ToString().GetHashCode()).Next(4); - вот тут из-за new Random мы будем нести дополнительные расходы ресурсов при создании нового объекта на каждой итерации цикла, и вот здесь Guid.NewGuid().ToString().GetHashCode() на каждой итерации цикла мы будем тратить дополнительные ресурсы, которые могли бы не тратить.

Мы хотим что-то вроде:
Random rand = new Random(Guid.NewGuid().ToString().GetHashCode());
и уже дальше в многопотоке дёргать только rand.Next(4), ожидая получить значения из диапазона 0,1,2,3 (но явно никак не 0 0 0 0 всегда или после какой-то сбойной итерации), тем самым не тратить ресурсы каждый раз на создание объекта и создание сиид, если это не нужно.
 
Последнее редактирование:
  • Спасибо
Реакции: Alexmd

Alexmd

Client
Регистрация
10.12.2018
Сообщения
1 021
Благодарностей
1 383
Баллы
113
В последнем коде, который Вы сбросили кроме var clipIndex = new Random(Guid.NewGuid().ToString().GetHashCode()).Next(4);, не менее важно, что экземпляр Рандом создается для каждого потока отдельно.
В том и суть. Вы правы. Это я и описал, также, словами. Я не полагаюсь на "псевдорандом" и подхват из него разными потоками одного и того же значения, а просто обхожу эту возможность генерируя свой экземпляр в каждом потоке.
В целом, я согласен, что метод не потоко-безопасен. Но я обхожу горы, на которые мне не вскарабкаться. Например, можно избавиться вообще от прямого использования рандома и получать такой же ожидаемый результат.
C#:
// Внимание! Из-за количества итераций и времени на вывод уведомление в лог - отрабатывать будет более 10 минут
string[] clips = new string[] { "1.mp3", "2.mp3", "3.mp3", "4.mp3"};
System.Threading.Tasks.Parallel.For(0, 10000000, (i) => {
    List<int> num = new List<int>(){1,2,3,0};
    num.Shuffle();
    var clipIndex = num.First();
    var clip = clips[clipIndex];
    if(i % 10000 == 0)
        project.SendInfoToLog(string.Format(@"{0} {1}",clip, clipIndex));
    
});
Как альтернатива.
Не вспомню где, но на форуме мы с Вами это уже обсуждали.
 
  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
В целом, я согласен, что метод не потоко-безопасен. Но я обхожу горы, на которые мне не вскарабкаться. Например, можно избавиться вообще от прямого использования рандома и получать такой же ожидаемый результат.
Да.
Я Вас понимаю.
Просто обозначил свою позицию - чтобы в случае чего её люди не смогли трактовать, будто проблемы нет.
Любой суп можно сварить разными способами.
Кстати, если дело в 4 элементах массива, то num.Shuffle(); также будет отличным решением, как и OrderBy(x=> Guid.NewGuid()), правда если количество элементов будет много - то уже будет не смешно (мы с Вами в личной переписке подобные финты вроде даже измеряли и на практике увидели разницу в производительности).

Собственно, я не претендую на истину в первой инстанции. Любые мои сообщения нужно рассматривать исключительно как плод моего воображения, частичного копипаста и личного опыта.
 
  • Спасибо
Реакции: Alexmd

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)