Подтвердить что ты не робот

Что происходит в многопоточной среде?

Что такое "Занятый поворот" в многопоточной среде?

Как это полезно и как его можно реализовать в java в многопоточной среде?

Каким образом это может быть полезно для повышения производительности приложения?

4b9b3361

Ответ 1

Некоторые из других ответов пропускают реальную проблему с оживленным ожиданием.

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

Это реальная проблема. Обычная программа пользовательского режима, работающая в обычной операционной системе, не имеет контроля над тем, какие потоки выполняются на каких процессорах, нормальная операционная система не имеет возможности сказать разницу между ожиданным потоком и потоком, который выполняет работу, и даже если ОС знала, что поток занят - ожидание, у него не будет никакого способа узнать, что ожидает поток.

Таким образом, вполне возможно, что занятый официант ждет много миллисекунд (практически вечность), ожидая события, в то время как единственный поток, который может сделать событие, будет сидеть на боковой линии (то есть в очереди выполнения), ожидая своей очереди использования CPU.

Ожидание занятости часто используется в системах, где существует жесткий контроль над тем, какие потоки выполняются на каких процессорах. Занятое ожидание может быть самым эффективным способом дождаться события, когда вы знаете, что поток, который вызовет его, фактически запущен на другом процессоре. Это часто случается, когда вы пишете код для самой операционной системы или когда вы пишете встроенное приложение реального времени, работающее под операционной системой реального времени.


Кевин Уолтерс писал о случае, когда время ожидания очень короткое. Обычная программа, работающая на процессоре, работающая на обычной ОС, может быть разрешена для выполнения миллионов инструкций в каждом временном фрагменте. Итак, если программа использует блокировку вращения для защиты критического раздела, состоящего всего из нескольких инструкций, маловероятно, что любой поток потеряет свой временной срез, пока он находится в критическом разделе. Это означает, что если нить A обнаружит блокировку блокировки вращения, то весьма вероятно, что поток B, который удерживает блокировку, фактически работает на другом процессоре. Поэтому, если вы знаете, что он будет запускаться на многопроцессорном хосте, вполне возможно использовать спин-блокировки в обычной программе.

Ответ 2

Ожидание ожидания или вращение - это метод, при котором процесс неоднократно проверяет, является ли условие истинным, а не вызывает метод ожидания или сна и освобождает процессор.

1.Это в основном полезно в многоядерном процессоре, где условие будет истинным довольно быстро, то есть в миллисекундах или микросекундах

2. Преимущество не выпускать CPU заключается в том, что все кэшированные данные и инструкции остаются незатронутыми, что может быть потеряно, если этот поток приостановлен на одном ядре и возвращен в другой поток

Ответ 3

"Занятый спин" постоянно зацикливается в одном потоке, чтобы увидеть, завершил ли другой поток некоторую работу. Это "плохая идея", поскольку она потребляет ресурсы, поскольку она просто ждет. Самые загруженные спины даже не спали в них, но вращаются как можно быстрее, ожидая завершения работы. Менее расточительно иметь ожидающую нить, уведомленную о завершении работы, и просто позволить ей спать до тех пор.

Примечание. Я называю это "Плохой идеей", но в некоторых случаях он используется для низкоуровневого кода для минимизации задержки, но это редко (если когда-либо) необходимо в коде Java.

Ответ 4

Занятое вращение/ожидание, как правило, плохая идея с точки зрения производительности. В большинстве случаев желательно спать и ждать сигнала, когда вы готовы к запуску, чем делать прядение. Возьмем сценарий, в котором есть два потока, и поток 1 ждет, пока поток 2 не установит переменную (скажем, он ждет до var == true. Затем он будет занят спином, просто делая

while (var == false)
    ;

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

НО, в редких случаях, когда время, которое вам нужно подождать, очень короткое, на самом деле быстрее для spinlock. Это из-за времени, которое требуется для выполнения функций signalng; прядение предпочтительнее, если время, затрачиваемое на спиннинг, меньше времени, необходимого для выполнения сигнализации. Таким образом, это может быть полезно и может фактически улучшить производительность, но это определенно не самый частый случай.

Ответ 5

Ожидание Спин - это то, что вы постоянно ждете, пока условие придет. Противоположность ожидает сигнала (например, прерывание потока путем уведомления() и wait()).

Существует два способа ожидания: первый полуактивный (sleep/yield) и активный (ожидание).

В режиме ожидания ожидания программа активно работает на холостом ходу, используя специальные операционные коды, такие как HLT или NOP, или другие операторы времени. Другие используют только цикл while, проверяющий условие, возвращающее true.

JavaFramework предоставляет методы Thread.sleep, Thread.yield и LockSupport.parkXXX() для потока, передающего процессор. Сон ждет определенное количество времени, но alwasy занимает миллисекунду, даже если была указана нано-секунда. То же самое можно сказать и о LockSupport.parkNanos(1). Thread.yield допускает разрешение 100 нс для моей примерной системы (win7 + i5 mobile).

Проблема с доходностью - это то, как она работает. Если система используется полностью, в моем тестовом сценарии может потребоваться до 800 мс (100 рабочих потоков, подсчитывающих число (a + = a;) неопределенно). Поскольку выход освобождает процессор и добавляет поток в конец всех потоков в своей группе приоритетов, выход поэтому нестабилен, если процессор не используется в определенной степени.

Ожидание занятости блокирует процессор (ядро) на несколько миллисекунд.

Java Framework (проверка реализации класса условий) использует активный (занятый) период ожидания периодов менее 1000 нс (1 микросекунда). В моей системе средний вызов System.nanoTime занимает 160 нс, так что ожидание - это как проверка состояния, потраченного 160 нс на nanoTime и повторение.

Итак, в основном инфраструктура Java (очереди и т.д.) имеет что-то вроде ожидания под микросекундным вращением и попадает в ожидаемый период в пределах N гранулярности, где N - количество наносекунд для проверки временных ограничений и ожидания одного мс или дольше (для моей текущей системы).

Таким образом, ожидание активной занятости увеличивает использование, но помогает в общей реактивности системы.

При сжигании процессорного времени следует использовать специальные инструкции, снижающие энергопотребление ядра, выполняющего длительные операции.

Ответ 6

Занятое вращение является одним из методов ожидания событий без освобождения CPU. Это часто делается для того, чтобы избежать потери данных в кэше процессора, который теряется, если поток приостановлен и возобновлен в другом ядре.

Итак, если вы работаете в системе с низкой задержкой, где в настоящее время в вашем потоке обработки заказов нет никакого порядка, вместо спящего или вызывающего wait(), вы можете просто зациклиться, а затем снова проверить очередь на новые сообщения. Это полезно только в том случае, если вам нужно подождать очень мало времени, например. в микросекундах или наносекундах.

Структура LMAX Disrupter, высокопроизводительная библиотека обмена сообщениями между потоками, имеет BusySpinWaitStrategy, которая основана на этой концепции и использует замкнутый цикл цикла для EventProcessors, ожидающих барьера.

Ответ 7

Занятое вращение - это не что иное, как цикл, пока нить не завершится. Например. Вы сказали 10 потоков, и вы хотите подождать, пока закончится весь поток, а затем хотите продолжить,

while(ALL_THREADS_ARE_NOT_COMPLETE);
//Continue with rest of the logic

Например, в java вы можете управлять несколькими потоками с помощью ExecutorService

    ExecutorService executor = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 10; i++) {
        Runnable worker = new WorkerThread('' + i);
        executor.execute(worker);
    }
    executor.shutdown();
    //With this loop, you are looping over till threads doesn't finish.
    while (!executor.isTerminated());

Это занятый спин, поскольку он потребляет ресурсы, поскольку процессор не сидит идеально, но продолжает работать над циклом. У нас должен быть механизм уведомления основной темы (родительский поток), чтобы указать, что все потоки выполнены, и он может продолжить оставшуюся часть задачи.

В предыдущем примере вместо того, чтобы заняться спином, вы можете использовать другой механизм для повышения производительности.

   ExecutorService executor = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 10; i++) {
        Runnable worker = new WorkerThread('' + i);
        executor.execute(worker);
    }
    executor.shutdown();
    try {
           executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    } catch (InterruptedException e) {
        log.fatal("Exception ",e);
    }