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

Сон() злой?

Прежде всего, существует много случаев, когда Sleep() неправильно используется, например, для "синхронизации" потоков или для регулярного опроса значения, которое будет выполнять функция уведомления (в Win32 WaitForSingleObject например)

Но как насчет других случаев использования? Является ли Sleep всегда злым? Если нет, то какие хорошие варианты использования для Sleep? Если да, почему почти все языки имеют какой-то оператор Sleep?

PS: Я задал этот вопрос из-за одного из комментариев другого вопроса. Там OP утверждает, что, по его мнению, Sleep следует избегать, как goto.

4b9b3361

Ответ 1

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

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

Ответ 2

Ive нашел хорошее применение для использования Thread.Sleep(1000); для моделирования латентности при написании обратного вызова в веб-приложении.

Простым примером с компонентами Microsoft AJAX является установка кнопки на панели обновления... в обработчике onclick используется Thread.Sleep(), тогда отобразится панель прогресса обновления.

Остановите удаление Thread.Sleep() при переходе в live...:)

Ответ 3

В реальном мире не всегда удобно использовать правильные примитивы синхронизации:

  • Иногда вам нужно опросить что-то до тех пор, пока не будет выполнено условие, и там вы используете sleep, чтобы избежать замачивания машины.

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

Изменить в ответ на комментарий Kieveli: я думаю, что вы должны реализовать надлежащую сигнализацию, когда сможете. Таким образом, рабочий поток должен делать блокировку, читаемую в очереди, а не сон и опрос. Я говорю, что иногда вы вынуждены взаимодействовать с системами, которые не позволяют делать правильные вещи. Я не говорю, что вы не должны беспокоиться о том, что правильно, когда это разумно возможно - "в течение половины секунды достаточно хорошо", может быть, но почти мгновенно будет заметно лучше!

Ответ 4

Тот же ответ, что и для всех остальных вопросов "это зло".

Это операция низкого уровня. Люди иногда используют операции низкого уровня, чтобы изобрести колеса, которые уже доступны как операции высокого уровня. Это неразумно, и вы должны убедиться, что это не то, что вы делаете. Но если вы на самом деле программируете на низком уровне, то, вероятно, вы будете использовать операции низкого уровня. Некоторые высокоуровневые программисты будут думать, что вы злы или глупы, или и то, и другое. Вы знаете лучше, и поскольку вы тот, кто пишет свои платформы высокого уровня, они могут либо заткнуться, либо сделать это сами.

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

Хорошее применение для сна:

  • Если вам нужно заблокировать до определенного времени (или на определенный период). Ваш язык/библиотеки/ОС может или не может содержать таймер блокировки, который выполняет задание. Если нет, то сон всегда доступен. Если это так, это, вероятно, будет делать то же самое, что и цикл сна со стандартом болота, так что идите с тем, что меньше кода.

  • При реализации других примитивов, таких как таймеры.

  • Когда вы используете сигналы для асинхронного межпоточного или межпроцессного обмена сообщениями на POSIX или что-то еще. Вы просто спите все время, а обработчики сигналов либо выполняют работу, либо задают состояние, чтобы сообщать вам, что нужно делать, и вы делаете это, когда вы просыпаетесь. Конечно, вы могли бы использовать другие API, но если вы не предпочитаете этот API, вы просто избегаете сна, потому что вам сказал чувак в Интернете. Возможно, когда он напишет язык программирования, который не спит, и лучше, чем ваш текущий язык, тогда вы переключитесь на это.

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

Ответ 5

Для реализации tail -f потребуется sleep(). т.е. stat() файл, если он изменился, прочитайте различия, затем sleep() для бит...... продолжайте до прерывания.

Я считаю это допустимым использованием sleep()

В качестве примера в Linux strace tail -f foo устанавливается

clock_gettime(CLOCK_REALTIME, {1247041913, 292329000}) = 0
nanosleep({1, 0}, NULL)                 = 0
fstat64(3, {st_mode=S_IFREG|0755, st_size=357, ...}) = 0
clock_gettime(CLOCK_REALTIME, {1247041914, 311933000}) = 0
nanosleep({1, 0}, NULL)                 = 0
fstat64(3, {st_mode=S_IFREG|0755, st_size=357, ...}) = 0
clock_gettime(CLOCK_REALTIME, {1247041915, 355364000}) = 0
....

OK это nanosleep(), но применяются те же правила.

Solaris truss tail -f foo располагается до

read(0, 0x00024718, 65537)                      = 0
nanosleep(0xFFBFF1A0, 0xFFBFF198)               = 0
read(0, 0x00024718, 65537)                      = 0
nanosleep(0xFFBFF1A0, 0xFFBFF198) (sleeping...)
nanosleep(0xFFBFF1A0, 0xFFBFF198)               = 0
read(0, 0x00024718, 65537)                      = 0

Ответ 6

Помимо целей тестирования, подобных тем, которые были упомянуты Chalkey, я обнаружил, что мне никогда не нужно называть сон на ОС высокого уровня, например Linux, Windows и OS/X, Даже в тех случаях, когда ожидается, что программа просто ждет определенное количество времени, я использую функцию ожидания в семафоре с таймаутом, чтобы я мог немедленно завершить поток, выпуская семафор, если что-то/кто-то просит мою программу завершить работу

# [pseudo-code]

if wait_semaphore(exit_signal_semaphore, time_to_sleep)
  # another thread has requested this one to terminate
  end_this_thread
else
  # event timed-out; wait_semaphore behaved like a sleep function
  do_some_task
end

Ответ 7

Я не вижу, чтобы это упоминалось здесь, но sleep() - это один из очень верных способов, чтобы дать процессорному времени срез более достойному процессу. Когда вы спите(), ОС берет контроль и решает, кто должен работать дальше, это позволяет также другим потокам из одного процесса иметь процессорное время. Это уменьшает давление ЦП на однопроцессорном компьютере, когда генерируется несколько потоков, и контроллер ожидает, что рабочие станут готовы.

Ответ 8

Если вы используете Sleep() для работы с любым случаем, включающим больше, чем только тот поток, в котором вы работаете, возможно, вы делаете что-то неправильно...

Тем не менее, есть моменты, когда вы хотите приостановить обработку, например, в бесконечном (или фактически так) рабочем цикле, чтобы дать другим процессам некоторую передышку.

Ответ 9

IMHO вы можете избежать сна(), когда у вас хорошо написана операционная система, и вы работаете в нормальном режиме ОС.

Когда вам приходится работать вне операционной системы (например, встроенное программное обеспечение/прошивка) и вне нормальных сфер (например, драйверов), у вас нет доступа к технологиям потоковой передачи, потому что для вас нет переключателя задач. Таким образом, у вас нет другого выбора, кроме как делать что-то вроде спинлоков и опрошенных, потому что нет никакого предпосылки прийти вам помочь.

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

Ответ 10

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

Ответ 11

Вызов sleep() можно почти всегда избегать. Ниже приведены некоторые сценарии в программе с циклом событий и несколькими потоками, так как это был бы самый распространенный сценарий sleep() - это (ab).

  • В качестве функции мониторинга/опроса (т.е. "wait-every-100-ms-before-repeating-this-function" ) - механизм ожидания может заменить сон. Тайм-аут по существу требует, чтобы обработчик основного события приложения вызывал функцию через определенное время. Это "напоминание" хранится во внутренней очереди и выполняется после истечения таймера. например:

    class DownloadMonitor 
    {
      int UpdateProgressBar();
      void Monitor()
      {
        if (UpdateProgressBar() < 100) 
        { 
          Application::SetTimeOut("100 ms", this, UpdateProgressBar); 
        }
      }
    }
    
    Это применимо для таких примеров, как "tail -f". Хорошо выполненный тайм-аут (например, проверка времени изменения файла) позволит пользователю контролировать программу между опросами. Одним из недостатков тайм-аута является то, что он ограничен потоками с циклами событий (обычно это основной поток).

  • Как механизм синхронизации потоков - это очень опасно, поскольку он оценивает время, затраченное на то, чтобы процессор обрабатывал что-то. Замените двоичные семафоры.

Простой пример семафоров и тайм-аутов:

  • Программное обеспечение для преобразования видео, как правило, имеет отдельные потоки для анализа изображений, ввода-вывода ввода-вывода и пользовательского интерфейса (позволяя такие команды, как "Запуск в фоновом режиме", "Отмена", "Пауза" и т.д.).

  • Анализ изображения должен завершиться до того, как на диск IO будет предложено записать преобразованную часть файла на диск, и это должно завершиться до того, как пользовательский интерфейс обновится.

  • Разрешить запуск обоих потоков в цикле. Поток DiskIO начинается с ожидания семафора "Finish Conversion". Анализ изображения может отправлять этот семафор, когда преобразованное изображение находится в очереди. Диск Disk IO записывает это изображение на диск, обновляет переменную типа "Percent Done" и снова ждет семафора. Поток пользовательского интерфейса периодически считывает переменную "Percent Done" с использованием механизма тайм-аута. Различные статусы пользовательского интерфейса устанавливаются пользовательским интерфейсом и проверяются по крайней мере один раз в каждом цикле с помощью потоков конверсий и дисков IO.

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

Ответ 12

Иногда вы не хотите постоянно обновлять свой дисплей, например, в системных или сетевых мониторах. Другим примером является watch (1) - как бы вы реализовали это без сна?

Ответ 13

В Java и .Net функция sleep() прерывается.

Итак, если вы спите(), а другой поток прерывает вас по желанию (вызывая перехват InterruptedException), нет ничего плохого в этом.

В настоящее время я пишу механизм опроса по какой-то внешней очереди - и мой код в основном:

while (true)
{
  items = takeFromQueue();
  if (items.size() == 0)
    sleep(1000);
}

И еще один поток может спокойно остановить этот поток, вызвав thread.interrupt();

Ответ 14

Windows: Обычно, если мне нужно сделать "sleep the thread", я бы не использовал sleep(), вместо этого я бы использовал MsgWaitForMultipleObjects или подобное, что позволяет указывать таймаут при ожидании уведомлений. Таким образом, поток может реагировать на любые события (например, WM_QUIT), не ожидая, когда поток выйдет из-под сна, проверьте событие и затем закройте.

Ответ 15

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

Ответ 16

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

Ответ 17

Все о том, как вы его используете.

В некотором коде, который мы используем на работе, один разработчик поставил спящий (5) 5 миллисекунд, с комментарием "sleep, так что мой ПК все еще годный к употреблению", который хорош, кроме наших клиентов, которые жалуются на скорость работы. Поэтому я удалил его, и пропускная способность удвоилась, но он вернул его в сон (0), жалуясь на то, что его машина перестала отвечать на запросы при большом тестировании загрузки данных. Groan, получите новый dev ПК

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

Ответ 18

Но как насчет других применений? Сон всегда зло? Если нет, то что хорошо использовать случаи сна?

Как насчет того, что вам нужно что-то делать каждые 10 минут, я не вижу ничего плохого, просто помещая вашу программу/нить в режим сна, пока не придет время снова работать.