Почему «-XX:+UseLWPSynchronization» может негативно повлиять на блокировку печати в ОС Windows?

Я хотел бы реализовать простой ограничитель скорости в java, чтобы научиться использовать jmh. Простой проект github создается по адресу https://github.com/William1104/rate-limiter.

Интересно, что на пропускную способность некоторых реализаций (со штампом) влияет включенная опция «-XX:+UseLWPSynchronization». Тест производительности выполнялся на компьютере с Windows, и я полагаю, что он не повлияет на систему, отличную от Solaris. Однако результат тестирования показывает другое. Могу ли я узнать, кто-нибудь может помочь мне понять, что именно происходит?

Вот результат тестирования на моей машине в качестве справки:

С опцией: -server, -XX:+UnlockDiagnosticVMOptions, -XX:+UseNUMA

Ориентир (тип ограничения скорости) Режим цент Счет Ошибка Единицы RaterLimiterBenchmark.thread_1 StampLockLongArrayRateLimiter угроза 90 21487.385 ▒ 1082,163 операций/мс RaterLimiterBenchmark.thread_1 StampLockInstantArrayRateLimiter угроза 90 13162.330 ▒ 1585,555 операций/мс RaterLimiterBenchmark.thread_1 Синхронизедлонгаррайрейтелимитер угроза 90 15362,934 ▒ 227 704 операций/мс RaterLimiterBenchmark.thread_1 СинхронизированныйInstantArrayRateLimiter угроза 90 17281.675 ▒ 2148,057 операций/мс RaterLimiterBenchmark.thread_10 StampLockLongArrayRateLimiter угроза 90 6868,653 ▒ 146,372 операций/мс RaterLimiterBenchmark.thread_10 StampLockInstantArrayRateLimiter угроза 90 8189,747 ▒ 335,517 операций/мс RaterLimiterBenchmark.thread_10 Синхронизедлонгаррайрейтелимитер угроза 90 6643.004 ▒ 103,568 операций/мс RaterLimiterBenchmark.thread_10 СинхронизированныйInstantArrayRateLimiter угроза 90 5252,975 ▒ 190,363 операций/мс RaterLimiterBenchmark.thread_100 StampLockLongArrayRateLimiter угроза 90 7352.890 ▒ 2109.446 операций/мс RaterLimiterBenchmark.thread_100 StampLockInstantArrayRateLimiter угроза 90 8675,814 ▒ 922,653 операций/мс RaterLimiterBenchmark.thread_100 Синхронизедлонгаррайрейтелимитер угроза 90 6509.368 ▒ 157,212 операций/мс RaterLimiterBenchmark.thread_100 СинхронизированныйInstantArrayRateLimiter угроза 90 5042.867 ▒ 192,971 операций/мс

С опцией: -server, -XX:+UnlockDiagnosticVMOptions, -XX:+UseNUMA, -XX:+UseLWPSynchronization

Ориентир (тип ограничения скорости) Режим цент Счет Ошибка Единицы RaterLimiterBenchmark.thread_1 StampLockLongArrayRateLimiter угроза 90 11383.198 ▒ 353,921 операций/мс RaterLimiterBenchmark.thread_1 StampLockInstantArrayRateLimiter угроза 90 11666,918 ▒ 842,426 операций/мс RaterLimiterBenchmark.thread_1 Синхронизедлонгаррайрейтелимитер угроза 90 15696,852 ▒ 371,078 операций/мс RaterLimiterBenchmark.thread_1 СинхронизированныйInstantArrayRateLimiter угроза 90 15357,617 ▒ 650,846 операций/мс RaterLimiterBenchmark.thread_10 StampLockLongArrayRateLimiter угроза 90 6937.050 ▒ 130,727 операций/мс RaterLimiterBenchmark.thread_10 StampLockInstantArrayRateLimiter угроза 90 8268,909 ▒ 291 471 операций/мс RaterLimiterBenchmark.thread_10 Синхронизедлонгаррайрейтелимитер угроза 90 9134.319 ▒ 1208,998 операций/мс RaterLimiterBenchmark.thread_10 СинхронизированныйInstantArrayRateLimiter угроза 90 5294.341 ▒ 225,995 операций/мс RaterLimiterBenchmark.thread_100 StampLockLongArrayRateLimiter угроза 90 8453,825 ▒ 1075,312 операций/мс RaterLimiterBenchmark.thread_100 StampLockInstantArrayRateLimiter угроза 90 16297,921 ▒ 611,255 операций/мс RaterLimiterBenchmark.thread_100 Синхронизедлонгаррайрейтелимитер угроза 90 12536.378 ▒ 974,951 операций/мс RaterLimiterBenchmark.thread_100 СинхронизированныйInstantArrayRateLimiter угроза 90 9051.560 ▒ 1303,856 операций/мс

Есть реализация StampLockLongArrayRateLimiter и SynchronizedLongArrayRateLImiter:

package one.williamwong.ratelimiter;

import java.time.Duration;
import java.util.Arrays;
import java.util.concurrent.locks.StampedLock;

public class StampLockLongArrayRateLimiter implements IRateLimiter {

    private final long duration;
    private final long[] records;
    private final StampedLock lock;
    private int pointer;

    public StampLockLongArrayRateLimiter(int maxInvokes, Duration duration) {
        this.duration = duration.toNanos();
        this.records = new long[maxInvokes];
        this.lock = new StampedLock();
        this.pointer = 0;
    }

    @Override public void acquire() {
        final long stamp = lock.writeLock();
        try {
            final long now = System.nanoTime();
            if (records[pointer] != 0) {
                final long awayFromHead = now - records[pointer];
                if (awayFromHead < duration) {
                    handleExcessLimit(records.length, Duration.ofNanos(awayFromHead));
                }
            }
            records[pointer] = now;
            pointer = (pointer + 1) % records.length;
        } finally {
            lock.unlockWrite(stamp);
        }
    }

    @Override public void reset() {
        final long stamp = lock.writeLock();
        try {
            Arrays.fill(records, 0);
            this.pointer = 0;
        } finally {
            lock.unlockWrite(stamp);
        }
    }

}
package one.williamwong.ratelimiter;

import java.time.Duration;
import java.util.Arrays;

public class SynchronizedLongArrayRateLimiter implements IRateLimiter {

    private final long duration;
    private final long[] records;
    private final Object lock;
    private int pointer;

    public SynchronizedLongArrayRateLimiter(int maxInvokes, Duration duration) {
        this.duration = duration.toNanos();
        this.records = new long[maxInvokes];
        this.lock = new Object();
        this.pointer = 0;
    }

    @Override
    public void acquire() {
        synchronized (lock) {
            final long now = System.nanoTime();
            if (records[pointer] != 0) {
                final long awayFromHead = now - records[pointer];
                if (awayFromHead < duration) {
                    handleExcessLimit(records.length, Duration.ofNanos(awayFromHead));
                }
            }
            records[pointer] = now;
            pointer = (pointer + 1) % records.length;
        }
    }

    @Override public void reset() {
        synchronized (lock) {
            Arrays.fill(records, 0);
            this.pointer = 0;
        }
    }

}
100 миллисекунд измерение для запуска 100 потоков? (мем "Это нормально")
apangin 26.12.2020 10:27
-XX:+UseLWPSynchronization действительно не влияет на Windows. И потому, что он даже не читается, и потому, что «истина» является значением флага по умолчанию.
apangin 26.12.2020 10:31

Привет @apangin, спасибо за ваш комментарий. Я перезапущу тест, чтобы убедиться, что то, что я наблюдал, стабильно. Могу ли я узнать, как долго должно быть измерение? Любая рекомендация или ссылка? Большое спасибо.

William Wong 26.12.2020 11:20
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
3
307
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Спасибо за ваш комментарий. Я перезапускаю тест с другими настройками. Если мы снова выполним JMH с 1 секундой для каждой итерации, я получу следующий результат:

С опцией: -server, -XX:+UnlockDiagnosticVMOptions, -XX:+UseNUMA, -XX:-UseLWPSynchronization

Ориентир (тип ограничения скорости) Режим цент Счет Ошибка Единицы RaterLimiterBenchmark.thread_1 StampLockLongArrayRateLimiter угроза 90 23573.282 ▒ 364 739 операций/мс RaterLimiterBenchmark.thread_1 StampLockInstantArrayRateLimiter угроза 90 23062.260 ▒ 1035,395 операций/мс RaterLimiterBenchmark.thread_1 Синхронизедлонгаррайрейтелимитер угроза 90 34667.411 ▒ 246.003 операций/мс RaterLimiterBenchmark.thread_1 СинхронизированныйInstantArrayRateLimiter угроза 90 36426.369 ▒ 1248,360 операций/мс RaterLimiterBenchmark.thread_10 StampLockLongArrayRateLimiter угроза 90 13592.158 ▒ 76,319 операций/мс RaterLimiterBenchmark.thread_10 StampLockInstantArrayRateLimiter угроза 90 14564.306 ▒ 474,613 операций/мс RaterLimiterBenchmark.thread_10 Синхронизедлонгаррайрейтелимитер угроза 90 13524.610 ▒ 155.850 операций/мс RaterLimiterBenchmark.thread_10 СинхронизированныйInstantArrayRateLimiter угроза 90 13080.967 ▒ 309 736 операций/мс RaterLimiterBenchmark.thread_100 StampLockLongArrayRateLimiter угроза 90 13224.529 ▒ 459.035 операций/мс RaterLimiterBenchmark.thread_100 StampLockInstantArrayRateLimiter угроза 90 13890,278 ▒ 456,182 операций/мс RaterLimiterBenchmark.thread_100 Синхронизедлонгаррайрейтелимитер угроза 90 12672,925 ▒ 314,118 операций/мс RaterLimiterBenchmark.thread_100 СинхронизированныйInstantArrayRateLimiter угроза 90 12245.120 ▒ 296,395 операций/мс

С опцией: -server, -XX:+UnlockDiagnosticVMOptions, -XX:+UseNUMA, -XX:+UseLWPSynchronization

Ориентир (тип ограничения скорости) Режим цент Счет Ошибка Единицы RaterLimiterBenchmark.thread_1 StampLockLongArrayRateLimiter угроза 90 24842,514 ▒ 372,521 операций/мс RaterLimiterBenchmark.thread_1 StampLockInstantArrayRateLimiter угроза 90 24327.864 ▒ 322,659 операций/мс RaterLimiterBenchmark.thread_1 Синхронизедлонгаррайрейтелимитер угроза 90 34490.411 ▒ 330,288 операций/мс RaterLimiterBenchmark.thread_1 СинхронизированныйInstantArrayRateLimiter угроза 90 38383.257 ▒ 654,269 операций/мс RaterLimiterBenchmark.thread_10 StampLockLongArrayRateLimiter угроза 90 13536.284 ▒ 74,613 операций/мс RaterLimiterBenchmark.thread_10 StampLockInstantArrayRateLimiter угроза 90 13702.022 ▒ 289 616 операций/мс RaterLimiterBenchmark.thread_10 Синхронизедлонгаррайрейтелимитер угроза 90 12530.107 ▒ 243,471 операций/мс RaterLimiterBenchmark.thread_10 СинхронизированныйInstantArrayRateLimiter угроза 90 10795,833 ▒ 158.400 операций/мс RaterLimiterBenchmark.thread_100 StampLockLongArrayRateLimiter угроза 90 13204.275 ▒ 200 937 операций/мс RaterLimiterBenchmark.thread_100 StampLockInstantArrayRateLimiter угроза 90 11606.823 ▒ 224,213 операций/мс RaterLimiterBenchmark.thread_100 Синхронизедлонгаррайрейтелимитер угроза 90 11504.124 ▒ 107,543 операций/мс RaterLimiterBenchmark.thread_100 СинхронизированныйInstantArrayRateLimiter угроза 90 10732.451 ▒ 118,753 операций/мс

Я не наблюдаю большой разницы в производительности, когда «UseLWPSynchronization» включена или нет. Проблема, которую я получил, связана с нестабильной настройкой JMH.

Другие вопросы по теме