Многопоточность, когда уронить против сна

Чтобы уточнить терминологию, выход - это когда поток отбрасывает свой временной срез. Моя платформа представляет интерес для потоков POSIX, но я думаю, что вопрос является общим.

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

Ответ 1

"Правильный" способ кодирования производителя/потребителя состоит в том, чтобы потребитель ожидал данные производителя. Вы можете добиться этого, используя объект синхронизации, такой как Mutex. Потребитель будет Wait на мьютексе, который блокирует его от выполнения до тех пор, пока не будут доступны данные. В свою очередь, производитель будет сигнализировать мьютекс, когда доступны данные, которые пробудят потребительский поток, чтобы он мог начать обработку. Это более эффективно, чем sleep в терминах:

  • Использование ЦП (нет циклов впустую) и
  • Время выполнения (выполнение начинается, как только данные доступны, а не когда поток запланирован для пробуждения).

Итак, вот анализ урожая против сна, который вы просили. Возможно, вам придется использовать такую ​​схему, если по какой-либо причине ожидание вывода не представляется возможным:

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

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

Ответ 2

сон и урожайность не совпадают. При вызове sleep процесс/поток передает CPU другому процессу/потоку на заданное количество времени.

yield возвращает ЦП другому потоку, но может немедленно вернуться, если нет других потоков, ожидающих ЦП.

Поэтому, если вы хотите регулировать скорость, например, при потоковой передаче данных через регулярные промежутки времени, используйте функции sleep или nanosleep.

Если необходима синхронизация между производителем/потребителем, вы должны использовать мьютекс/условное ожидание.

Ответ 3

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

Уступка в этой ситуации не очень помогает, потому что вероятность случайного отката может увеличить вероятность того, что голодание нити не произойдет.

Редактировать: Хотя я знаю, что это не обязательно Java-специфический. Java-реализация Thread.sleep(0) имеет тот же эффект, что и Thread.yield() На этом этапе это скорее вопрос стиля.

Ответ 4

В java некоторые реализации JVM рассматривают Thread.yield() как no-op, что означает, что это может не иметь эффекта. Вызов Thread.sleep() не обязательно означает, что планировщик должен давать CPU другому потоку; это тоже зависит от реализации. Он может переключиться в контекстном режиме на другой поток, который ждет, или он не может, чтобы амортизировать затраты, связанные с контекст-коммутатором.