Является сон () злом?

Действительно установите Testdriven.net для интеграции NUnit с Visual Studio. MbUnit и более поздние версии NUnit также содержат шаблоны проекта для модульных тестов.

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

40
задан Community 23 May 2017 в 10:34
поделиться

18 ответов

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

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

40
ответ дан 27 November 2019 в 01:10
поделиться

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

0
ответ дан 27 November 2019 в 01:10
поделиться

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

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

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

0
ответ дан 27 November 2019 в 01:10
поделиться

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

1
ответ дан 27 November 2019 в 01:10
поделиться

В Java и .Net, sleep () можно прерывать.

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

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

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

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

1
ответ дан 27 November 2019 в 01:10
поделиться

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

1
ответ дан 27 November 2019 в 01:10
поделиться

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

  1. Как функция мониторинга / опроса (т.е. 'wait-every-100-ms-before-repeat-this-function') - механизм тайм-аута может заменить сон. По сути, тайм-аут требует, чтобы основной обработчик событий приложения вызвал функцию через определенное время. Это «напоминание» хранится во внутренней очереди и выполняется по истечении таймера. например:

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

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

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

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

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

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

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

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

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

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

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

    Анализ изображений может отправить этот семафор, когда преобразованное изображение находится в очереди. Поток Disk IO записывает это изображение на диск, обновляет переменную типа «Percent Done» и снова ожидает семафор. Поток пользовательского интерфейса периодически считывает переменную «Выполнено в процентах», используя механизм тайм-аута. Различные статусы пользовательского интерфейса устанавливаются пользовательским интерфейсом и проверяются по крайней мере один раз в каждом цикле потоками преобразования и дискового ввода-вывода.

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

    Анализ изображений может отправить этот семафор, когда преобразованное изображение находится в очереди. Поток Disk IO записывает это изображение на диск, обновляет переменную типа «Percent Done» и снова ожидает семафор. Поток пользовательского интерфейса периодически считывает переменную «Выполнено в процентах», используя механизм тайм-аута. Различные статусы пользовательского интерфейса устанавливаются пользовательским интерфейсом и проверяются по крайней мере один раз в каждом цикле потоками преобразования и дискового ввода-вывода.

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

    Различные статусы пользовательского интерфейса устанавливаются пользовательским интерфейсом и проверяются по крайней мере один раз в каждом цикле потоками преобразования и дискового ввода-вывода.

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

    Различные статусы пользовательского интерфейса устанавливаются пользовательским интерфейсом и проверяются по крайней мере один раз в каждом цикле потоками преобразования и дискового ввода-вывода.

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

    2
    ответ дан 27 November 2019 в 01:10
    поделиться

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

    2
    ответ дан 27 November 2019 в 01:10
    поделиться

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

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

    4
    ответ дан 27 November 2019 в 01:10
    поделиться

    But what about other uses? Is Sleep always evil? If no, what are good use cases for Sleep?

    How about you need to do something every 10 minutes, I don't see anything wrong with just putting your program/thread to sleep until it is time to work again.

    0
    ответ дан 27 November 2019 в 01:10
    поделиться

    Same answer as for all the other "is it evil" questions.

    It's a low-level operation. People sometimes use low-level operations to reinvent wheels which are already available as high-level operations. This is unwise, and you should make sure it's not what you're doing. But if you're actually programming at a low level, then you will probably be using low-level operations. Some high-level programmers will think you're evil or stupid or both. You know better, and since you're the one who writes their high-level platforms, they can either shut up or do it themselves.

    Given a choice between a wicked contortion using a high-level construct, and a wicked contortion using a low-level construct, some people think you should always prefer the former. I don't really get their POV, but they are at least consistent, so you can't blame them unless the latter is demonstrably faster/smaller/better.

    Good uses for sleep:

    • When you have to block until a certain time (or for a certain period). Your language/libraries/OS may or may not offer a blocking timer that does the job. If not, then sleep is the always-available option. If so, it will probably do exactly the same thing that the bog-standard sleep loop does anyway, so go with whatever is less code.

    • When implementing other primitives such as timers.

    • When you're using signals for asynchronous inter-thread or inter-process messaging on POSIX or whatever. You just sleep all the time, and signal handlers either do the work, or set state to tell you what work needs doing and you do it when you wake up. Of course you could use other APIs instead, but unless you actively prefer that API, then you'd just be avoiding sleep because some dude on the internet told you to. Maybe when he writes a programming language that doesn't have sleep, and is better than your current language, then you'll switch to that.

    The main problem with sleep (aside from that it doesn't really do much interaction between threads, so is usually the wrong tool for jobs requiring that) is that even though you're not consuming any CPU time, you're still consuming resources because you have a thread sitting around doing nothing. Depending on platform, threads might be expensive. On a single-core system, the second thread of two is especially expensive, since if you can get rid of it most of your data synchronisation problems go away. So if you can reasonably design your app such that it never needs multiple threads, and never blocks except in some event loop, because everything is done with asynchronous messages, then do so, and you won't be needing sleep.

    8
    ответ дан 27 November 2019 в 01:10
    поделиться

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

    # [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
    
    5
    ответ дан 27 November 2019 в 01:10
    поделиться

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

    I будет считать это допустимым использование 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
    ....
    

    Хорошо, это 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
    
    7
    ответ дан 27 November 2019 в 01:10
    поделиться

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

    5
    ответ дан 27 November 2019 в 01:10
    поделиться

    In реальный мир, это Не всегда практично использовать правильные примитивы синхронизации:

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

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

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

    19
    ответ дан 27 November 2019 в 01:10
    поделиться

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

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

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

    2
    ответ дан 27 November 2019 в 01:10
    поделиться

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

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

    Очевидно, удалите Thread.Sleep () при запуске ... :)

    20
    ответ дан 27 November 2019 в 01:10
    поделиться

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

    1
    ответ дан 27 November 2019 в 01:10
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: