1. Этот сайт использует файлы cookie. Продолжая пользоваться данным сайтом, Вы соглашаетесь на использование нами Ваших файлов cookie. Узнать больше.
Скрыть объявление

Привет посетитель! У нас на форуме тебе откроются дополнительные разделы, которые скрыты от гостей! А так же ты найдёшь много полезной информации.

Прочее Упрощенная библиотека Rnd 1.2

На основе ThreadLocalRandom

  1. Hacky

    Hacky Интересующийся Местный

    Регистрация:
    28 мар 2016
    Сообщения:
    57
    Симпатии:
    78
    Баллы:
    215
    Пользователь Hacky разместил новый ресурс:

    Упрощенная библиотека Rnd - На основе Math.random

    Узнать больше об этом ресурсе...
     
    kick, Elastic Heart и ItCry нравится это.
  2. velafrys

    velafrys Интересующийся Местный

    Регистрация:
    4 фев 2016
    Сообщения:
    124
    Симпатии:
    82
    Баллы:
    234
    Птицы пели за окном, молодые пары кружились на набережной в непонятном веселье, но уж точно не в Вихре Мерсенна
    Беззаботный апрель... никто не хотел использовать seed и нормальные форматы для архивации файлов
     
  3. Hacky

    Hacky Интересующийся Местный

    Регистрация:
    28 мар 2016
    Сообщения:
    57
    Симпатии:
    78
    Баллы:
    215
    kick нравится это.
  4. Hacky

    Hacky Интересующийся Местный

    Регистрация:
    28 мар 2016
    Сообщения:
    57
    Симпатии:
    78
    Баллы:
    215
    Чтобы получить тру рандом можете в коде заменить Math.random() на ThreadLocalRandom.current().nextDouble() но это будет более затратно по производительности.
     
    Последнее редактирование: 7 апр 2016
    kick нравится это.
  5. n3k0Nation

    n3k0Nation Antihero Пользователь

    Регистрация:
    30 май 2015
    Сообщения:
    479
    Симпатии:
    1.313
    Баллы:
    0
    Мне тут на ушко нашептали, что MersenneTwister (Colt 1.2.0 - API Specification) одобрено математиками сего мира и работает быстрее рандома "из коробки".
     
    Hacky нравится это.
  6. Java-man

    Java-man Пляшущий с бубном Пользователь

    Регистрация:
    6 сен 2015
    Сообщения:
    25
    Симпатии:
    50
    Баллы:
    152
    ThreadLocalRandom в данный момент самый быстрый генератор рандомных чисел в явке. Что в однопоточной среде, что в многопоточной (да, самое классное в ThreadLocalRandomе это что он потокобезопасен из коробки). Так что не вижу смысла использовать какие-то другие генераторы, если только вы не сидите на явке 6.

    Поспорил бы с этим утверждением, но мне пока лень писать бенчмарки, так что просто поверьте на слово. :-)
     
    Последнее редактирование: 6 апр 2016
    Enmity, Hacky и kick нравится это.
  7. Hacky

    Hacky Интересующийся Местный

    Регистрация:
    28 мар 2016
    Сообщения:
    57
    Симпатии:
    78
    Баллы:
    215
    Самому стало интересно, написал несколько небольших бенчмарков.
    Процессор i7 3630qm - 4 физических ядра, 8 логических. Компил и запуск через Intellij Idea 15, Java 8, win 10 x64.

    Скорость
    Описание: за 1 тест получаем 1 000 000 случайных чисел и считаем миллисы, затраченные на генерацию. В случае однопоточного теста всегда ждем окончание предыдущего потока теста с помощью join(), после чего стартуем новый. В случае мультипоточного все тесты запускаются в отдельном потоке одновременно.
    Для каждого участника будет выполнено 100 однопточных и многопоточных тестов, после чего рассчитано их среднее время выполнения, которое будет принято за результат (меньше - лучше).

    Math.random() - Получение случайного Double числа от 0 до 1:
    Single test of millon calculations = 29.0
    One-thread test - avg time of million calculations 100 times = 24.59
    Multi-thread test - avg time of million calculations 100 times = 21410.09

    ThreadLocalRandom.current().nextDouble() - Получение случайного Double числа от 0 до 1:
    Single test of millon calculations = 10.0
    One-thread test - avg time of million calculations 100 times = 2.19
    Multi-thread test - avg time of million calculations 100 times = 18.07
    UPD:
    Заметил интересную закономерность - чем больше потоков, тем быстрее обработка, так например среднее время генерации в 10 000 потоках равно 2.0901

    MersenneTwister.makeDefault().nextDouble() - Получение случайного Double числа от 0 до 1:
    Single test of millon calculations = 2861.0
    One-thread test - avg time of million calculations 100 times = 2665.28
    Multi-thread test - avg time of million calculations 100 times = 49829.57
    UPD: В мульти-тред тесте процесс сначала секунд 40 висел, а потом достаточно быстро все рассчитал

    В плане производительности бесспорный победитель ThreadLocalRandom


    Качество
    Описание: качество псевдо-рандома определяется частотой попадания в каждую часть своего диапазона. Например если мы условно поделим Double диапазон [от 0 до 10] на 10 равных частей, то получим одинаковые промежутки [от 0 до 1], [от 3 до 4] и тд. Чем меньше разница между частотой попадания в каждый из этих условных промежутков, тем точнее будет случайная выборка. Т.е. условно 10% на попадание в каждый промежуток. Соответственно Integer выборка псвевдо-рандома от 0 до 1 с 50% шансом должна выводить 1. А в промежутке от 0 до 3 шанс выпадения определенного числа должен быть равен 25%. Более подробно тут Дискретное равномерное распределение — Википедия
    В тесте будет высчитана средняя частота попадания в каждый из 100 промежутков на основании 10 тестов с 1 000 000 000 генераций рандомного числа. После чего средняя частота будет сравниваться с частотой каждого промежутка для получения средней разницы, которая станет результатом (среднее значение от среднего значения, кек). Так же будет рассчитана простая разница между максимальной и минимальной частотой и еще че нить. Для упрощения сгенерированные числа будут домножаться на 100 и конвертироваться в Integer. Обработка будет идти одним потоком. Погрешность ~5%

    Math.random():
    Avg rate diff = 25.196
    Avg rate = 1000.0
    Min rate = 911.8
    Max rate = 1077.7
    Avg rate diff between min & max = 994.75

    ThreadLocalRandom.current().nextDouble():
    Avg rate diff = 26.032
    Avg rate = 1000.0
    Min rate = 921.4
    Max rate = 1076.9
    Avg rate diff between min & max = 999.15

    MersenneTwister.makeDefault().nextDouble():
    Avg rate diff = 76.4779
    Avg rate = 1000.0
    Min rate = 771.8
    Max rate = 1260.1
    Avg rate diff between min & max = 1015.95

    С незначительным перевесом побеждает самый простейший Math.random. Что самое интересное - библиотека одобренная математиками имеет в разы более худшую выборку и гораздо больший разброс по частоте использования промежутков по сравнению со стандартными библиотеками явы. Вполне возможно, что это какой-то очень узко-специализированный рандомайзер, но для сервера ла2 ни в плане производительности, ни в плане качества выборки он не подходит.

    Выводы: самым оптимальным вариантом будет использование ThreadLocalRandom т.к. на сервере ла2 его производительность будет в разы выше любого рандомайзера при весьма годной выборке.

    P.S. Библиотека переведена на ThreadLocalRandom и обновлена.
     
    kick, Psycho, 6yka и 3 другим нравится это.
  8. 6yka

    6yka я уловил твоё излучение... Проверенный

    Регистрация:
    7 ноя 2015
    Сообщения:
    1.417
    Симпатии:
    839
    Баллы:
    685
    нихрена не понял, но кажись кому то утерли нос....
     
  9. Enmity

    Enmity jopacode.ru Администратор

    Регистрация:
    18 май 2015
    Сообщения:
    1.470
    Симпатии:
    1.161
    Баллы:
    1.044
    спасибо @Hacky , действительно полезная инфа.
     
  10. n3k0Nation

    n3k0Nation Antihero Пользователь

    Регистрация:
    30 май 2015
    Сообщения:
    479
    Симпатии:
    1.313
    Баллы:
    0
    Круто, хороший ресерч, поставил бы еще один плюс в репутацию, но чертовы лимиты, не дают этого сделать. И да, ты угадал, данная библиотека используется в специфичных вещах, например, в онлайн-казино.

    UPD: Кстати, по возможности, добавь еще тестирование SecureRandom или-как-там-его.
     
  11. Java-man

    Java-man Пляшущий с бубном Пользователь

    Регистрация:
    6 сен 2015
    Сообщения:
    25
    Симпатии:
    50
    Баллы:
    152
    @Hacky выложи тесты а то что-то не верится что разница в скорости НАСТОЛЬКО огромна.
     
    velafrys нравится это.
  12. Hacky

    Hacky Интересующийся Местный

    Регистрация:
    28 мар 2016
    Сообщения:
    57
    Симпатии:
    78
    Баллы:
    215
    Что касается SecureRandom, то он невероятно медленный. Тесты производительности я проводить не стал, т.к. его окончания я бы дождался только к пенсии :eek:
    QualityTest на основе 10 тестов со 100 000 повторениями:
    Avg rate diff = 25.536
    Avg rate = 1000.0
    Min rate = 926.3
    Max rate = 1076.3
    Avg rate diff between min & max = 1001.3
    В общем что-то среднее между Math.random и ThreadLocalRandom, а так же очень медленное.

    Прикладываю сурс.
    UPD: мульти-тред тест в приложенном сурсе на самом деле не мульти-тред. Перед написанием поста моча в голову ударила. В любом случае завтра перепишу его нормально
     

    Вложения:

    Последнее редактирование: 8 апр 2016
    kick нравится это.
  13. Hacky

    Hacky Интересующийся Местный

    Регистрация:
    28 мар 2016
    Сообщения:
    57
    Симпатии:
    78
    Баллы:
    215
    Финальная версия бенчмарка. Запилил полноценную платформу для добавления новых тестов (если захотите продолжить), а так же мульти-тред тест теперь ловит ошибки асинхронности при использовании ThreadLocalRandom.
    Требуется ява не ниже 8.
     

    Вложения:

    kick и ItCry нравится это.
  14. Java-man

    Java-man Пляшущий с бубном Пользователь

    Регистрация:
    6 сен 2015
    Сообщения:
    25
    Симпатии:
    50
    Баллы:
    152
    @Hacky увидел что у тебя бенчмарки не на jmh - решил переписать.

    И вот результаты:

    Score - кол-во потраченных наносекунд на одну операцию
    Score error - погрешность

    apacheMersenneTwisterRandom - реализация MersenneTwister с библиотеки commons math3
    coltMersenneTwisterRandom - реализация MersenneTwister с библиотеки cern
    oldRandom - стандартный явовский рандом (java.util.Random)
    threadLocalRandom - новый явовский рандом (java.util.concurrent.ThreadLocalRandom)

    В многопоточном бенчмарке все рандомы, кроме ThreadLocalRandom, были обернуты в ThreadLocal для потокобезопасности.

    Однопоточный бенчмарк
    Код:
    Benchmark                                                 Mode  Samples  Score  Score error  Units
    j.SingleThreadRndBenchmark.apacheMersenneTwisterRandom    avgt       20  4,791        0,164  ns/op
    j.SingleThreadRndBenchmark.coltMersenneTwisterRandom      avgt       20  3,373        0,041  ns/op
    j.SingleThreadRndBenchmark.oldRandom                      avgt       20  8,598        0,070  ns/op
    j.SingleThreadRndBenchmark.threadLocalRandom              avgt       20  1,734        0,054  ns/op
    
    Многопоточный бенчмарк (32 потока)
    Код:
    Benchmark                                                Mode  Samples   Score  Score error  Units
    j.MultiThreadRndBenchmark.apacheMersenneTwisterRandom    avgt       20  57,296        1,888  ns/op
    j.MultiThreadRndBenchmark.coltMersenneTwisterRandom      avgt       20  49,314        0,301  ns/op
    j.MultiThreadRndBenchmark.oldRandom                      avgt       20  45,541        0,466  ns/op
    j.MultiThreadRndBenchmark.threadLocalRandom              avgt       20  13,690        0,133  ns/op

    В итоге можно сделать простой вывод: используйте всегда ThreadLocalRandom и не ебите мозг.


    Код:
    import org.apache.commons.math3.random.MersenneTwister;
    import org.openjdk.jmh.annotations.*;
    import org.openjdk.jmh.infra.Blackhole;
    import org.openjdk.jmh.results.format.ResultFormatType;
    import org.openjdk.jmh.runner.Runner;
    import org.openjdk.jmh.runner.RunnerException;
    import org.openjdk.jmh.runner.options.Options;
    import org.openjdk.jmh.runner.options.OptionsBuilder;
    
    import java.util.Random;
    import java.util.concurrent.ThreadLocalRandom;
    import java.util.concurrent.TimeUnit;
    
    @State(Scope.Thread)
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public class SingleThreadRndBenchmark
    {
        private static final Random oldRandom = new Random();
        private static final MersenneTwister apacheMersenneTwisterRandom = new MersenneTwister();
        private static final cern.jet.random.engine.MersenneTwister coltMersenneTwisterRandom = new cern.jet.random.engine.MersenneTwister();
    
        @Benchmark
        public void threadLocalRandom(Blackhole bh)
        {
            int nextInt = ThreadLocalRandom.current().nextInt();
            bh.consume(nextInt);
        }
    
        @Benchmark
        public void oldRandom(Blackhole bh)
        {
            int nextInt = oldRandom.nextInt();
            bh.consume(nextInt);
        }
    
        @Benchmark
        public void apacheMersenneTwisterRandom(Blackhole bh)
        {
            int nextInt = apacheMersenneTwisterRandom.nextInt();
            bh.consume(nextInt);
        }
    
        @Benchmark
        public void coltMersenneTwisterRandom(Blackhole bh)
        {
            int nextInt = coltMersenneTwisterRandom.nextInt();
            bh.consume(nextInt);
        }
    
        public static void main(String[] args) throws RunnerException
        {
            Options opt = new OptionsBuilder()
                    .include(SingleThreadRndBenchmark.class.getSimpleName())
                    .warmupIterations(20)
                    .measurementIterations(20)
                    .result("result2.txt")
                    .resultFormat(ResultFormatType.TEXT)
                    .output("log2.txt")
                    .build();
    
            new Runner(opt).run();
        }
    
    }
    Код:
    import org.apache.commons.math3.random.MersenneTwister;
    import org.openjdk.jmh.annotations.*;
    import org.openjdk.jmh.infra.Blackhole;
    import org.openjdk.jmh.results.format.ResultFormatType;
    import org.openjdk.jmh.runner.Runner;
    import org.openjdk.jmh.runner.RunnerException;
    import org.openjdk.jmh.runner.options.Options;
    import org.openjdk.jmh.runner.options.OptionsBuilder;
    
    import java.util.Random;
    import java.util.concurrent.ThreadLocalRandom;
    import java.util.concurrent.TimeUnit;
    
    @State(Scope.Thread)
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public class MultiThreadRndBenchmark
    {
        private static final ThreadLocal<Random> oldRandom = new ThreadLocal<>().withInitial(Random::new);
        private static final ThreadLocal<MersenneTwister> apacheMersenneTwisterRandom
                = new ThreadLocal<>().withInitial(MersenneTwister::new);
        private static final ThreadLocal<cern.jet.random.engine.MersenneTwister> coltMersenneTwisterRandom
                = new ThreadLocal<>().withInitial(cern.jet.random.engine.MersenneTwister::new);
    
        @Benchmark
        public void threadLocalRandom(Blackhole bh)
        {
            int nextInt = ThreadLocalRandom.current().nextInt();
            bh.consume(nextInt);
        }
    
        @Benchmark
        public void oldRandom(Blackhole bh)
        {
            int nextInt = oldRandom.get().nextInt();
            bh.consume(nextInt);
        }
    
        @Benchmark
        public void apacheMersenneTwisterRandom(Blackhole bh)
        {
            int nextInt = apacheMersenneTwisterRandom.get().nextInt();
            bh.consume(nextInt);
        }
    
        @Benchmark
        public void coltMersenneTwisterRandom(Blackhole bh)
        {
            int nextInt = coltMersenneTwisterRandom.get().nextInt();
            bh.consume(nextInt);
        }
    
        public static void main(String[] args) throws RunnerException
        {
            Options opt = new OptionsBuilder()
                    .include(MultiThreadRndBenchmark.class.getSimpleName())
                    .warmupIterations(20)
                    .measurementIterations(20)
                    .threads(Runtime.getRuntime().availableProcessors() * 4)
                    .forks(1)
                    .result("result1.txt")
                    .resultFormat(ResultFormatType.TEXT)
                    .output("log1.txt")
                    .build();
    
            new Runner(opt).run();
        }
    
    }
     
    kick, Enmity и n3k0Nation нравится это.
  15. n3k0Nation

    n3k0Nation Antihero Пользователь

    Регистрация:
    30 май 2015
    Сообщения:
    479
    Симпатии:
    1.313
    Баллы:
    0
    Нет! Ты не заставишь меня! Никогда!!
     
    GenCloud нравится это.
  16. echipachenko

    echipachenko Пляшущий с бубном Open Source
    Contributor

    Регистрация:
    16 ноя 2015
    Сообщения:
    11
    Симпатии:
    13
    Баллы:
    117
    TC-у:

    Надеюсь Вы понимаете разницу между псевдослучайными величинами и случайными величинами....
    ИМХО: говоря о том, что Ваш рандом покажет "ТРУ" шансы - вы сильно ошибаетесь. Он ничем не лучше. Ибо он тоже ПСЕВДО случайный... На хабре есть много интересных статей по поводу псевдослучайных и случайных величин.

    А вот удобнее ли Ваш рандом? Это уже другой вопрос.
     
    Последнее редактирование: 11 апр 2016
  17. Hacky

    Hacky Интересующийся Местный

    Регистрация:
    28 мар 2016
    Сообщения:
    57
    Симпатии:
    78
    Баллы:
    215
    Ну как бы в топике и шла речь исключительно о псевдо рандоме, что я многократно подчеркивал, так же это написано в документации к каждому из представленных рандомайзеров. Под "тру" шансами я имел ввиду лучшие, чем были, что, кстати, не подтвердилось тестами.
    Я уже написал собственное тестирование качества случайной последовательности, лучшие результаты в котором показали Math.random и ThreadLocalRandom (сурс приложен) и вы говорите, что они ничем не лучше?