Почему thread sleep не работает

Thread.Sleep не работает

Всем привет!
Задача такая есть таймер который запускается каждый 30 сек и делает рассылку и уведомление Но когда наступает время (1 мин = 30 сек) он по почтам отправляет по 2 писем ( Как мне его задержат хотя бы на минуту ? почему это Thread.Sleep(60000); не работает ?

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Как использовать Thread.Sleep(5000), ошибка: «Элемент «Thread» не существует в текущем контексте»
я так понимаю, что Thread.Sleep(5000); это «тормоз» процесса выполенения программы на 5 сек? А.

Thread.Sleep
Итак, есть примерно вот такой консольный код: static void Main(string args) < .

Thread.Sleep и lock
Что будет если вызвать Thread.Sleep() внутри блока кода lock?

Аналог Thread.Sleep в Task
Имеется пример который запускает пару потоков с задержкой. using System; using.

Почему нельзя завести второй таймер, который вызовется раз в минуту?

Добавлено через 6 минут

Если не хотите запускать второй таймер, то можно так.

Thread.Sleep под капотом
Доброго времени суток! Собственно, весь вопрос в описании темы. Погуглил — мало информации и.

Странное поведение Thread.Sleep
Забавно, уже не первый раз встречаю такую вещь: делаю движение контрола по форме в цикле.

ProgressBar связать с thread.sleep
как получать progressbar.Value в случае когда стоит задержка в 10 секунд и надо в прогресс бар.

Суммируется ли задержка двух Thread.Sleep
Подскажите а Thread.Sleep суммируется или нет? 240000+60000=300000 или будет 240000 ? if.

Источник

Thread. Sleep Метод

Определение

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

Приостанавливает текущий поток на заданное время.

Перегрузки

Приостанавливает текущий поток на заданное количество миллисекунд.

Приостанавливает текущий поток на заданное время.

Sleep(Int32)

Приостанавливает текущий поток на заданное количество миллисекунд.

Параметры

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

Исключения

Значение времени ожидания является отрицательной величиной и не равно Infinite.

Примеры

В следующем примере метод используется Sleep для блокировки основного потока приложения.

Комментарии

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

Можно указать Timeout.Infinite для параметра, millisecondsTimeout чтобы приостановить поток в течение неограниченного времени. Однако System.Threading Mutex Monitor EventWaitHandle Semaphore для синхронизации потоков или управления ресурсами рекомендуется использовать другие классы, такие как,, или.

Системные тактовые импульсы с заданной скоростью, называемой разрешением часов. Фактическое время ожидания может быть не равно указанному времени ожидания, так как указанное время ожидания будет изменено в соответствии с тактами времени. дополнительные сведения о разрешении часов и времени ожидания см. в разделе функция Sleep из Windows системных api.

Этот метод не выполняет стандартные конвейеры COM и SendMessage.

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

Источник

Почему Thread.Sleep ведёт себя неправильно? Как мне сделать задержку или длинные вычисления в графической программе?

Мне нужно выводить информацию пользователю с задержкой. К примеру, менять содержимое текстовой метки каждую секунду. (Или выводить промежуточные результаты длинных вычислений.) В программах командной строки я делал так:

Это работало. Теперь мне нужно сделать то же самое в графической программе. Я написал метод

но он работает как-то не так. Промежуточные значения не показываются, а программа надолго перестаёт реагировать. А когда она отвисает, сразу показывает последнее значение.

Читайте также:  Не работает электрическая сигарета

Что происходит? Почему программа ведёт себя неправильно, и как же сделать правильно?

4 ответа 4

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

Всё это работает в одном и том же потоке, который называется UI-потоком.

Теперь, что происходит, если мы в UI-потоке выполняем Thread.Sleep(1000) ? А вот что: поток блокируется и ничего не делает целую секунду. Эту самую секунду наш цикл сообщений простаивает, потому что поток выполнения заблокирован нами! Эту секунду не обрабатываются оконные сообщения, не происходит реакция на мышь, не вызываются колбеки, и даже не перерисовывается содержимое окна — ведь всё это делается в том же самом цикле сообщений, который мы и заблокировали!

Чтобы программа работала нормально, наши обработчики событий (наподобие OnClick ), конструкторы объектов, и вообще весь код, бегущий в UI-потоке, должны пробегать максимально быстро, без задержек.

Как же сделать паузу в одну секунду? К счастью, в современной версии языка (начиная с C# 5) есть простое решение. Это async/await. Сделаем наш обработчик асинхронным (ключевое слово async ), и заменим Thread.Sleep на await Task.Delay :

Этот метод работает правильно!¹

Что же произошло? Дело в том, что await Task.Delay на время ожидания не блокирует поток. На время ожидания метод как бы прекращает своё выполнение, и цикл сообщений больше не блокируется. [Будьте внимательны, он может быть заблокирован ещё где-то.] Когда ожидание оканчивается, цикл сообщений возобновляет выполнение метода с прерванной точки, до следующего await или до конца метода.²

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

А что делать, если вместо задержки нужно выполнить какие-то вычисления? Их так просто не вырезать из хода выполнения функции, они всё равно должны быть выполнены. Для этих целей их можно выгрузить в другой поток. Не пугайтесь, это очень просто. Вместо кода

вы пишете вот что:

Task.Run выполняет ваш код в фоновом потоке, а на время этого выполнения функция опять-таки не блокирует UI-поток.³ Профит! Обратите только внимание на то, что из фонового потока нельзя считывать значения из контролов, поэтому их нужно считать заранее:

В более старых версиях языка, без async/await, приходилось достигать того же самого более сложным образом. Например, заводить таймер, подписываться на его тики, и на них менять значения в контролах. При этом локальные переменные приходилось выносить в поля класса (или в специальную структуру-контекст). Или можно было делать грязные трюки с DoEvents . К счастью, те старые недобрые времена давно прошли.

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

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

³ Если нужно делать большую и длительную работу в фоновом потоке, то, возможно, имеет смысл выгрузить эту работу целиком и сообщать о результатах в UI через Progress .

Источник

Как пользоваться Thread.sleep на JVM без блокировки

У таких языков JVM, как Java и Scala, есть возможность запускать параллельный код с помощью класса Thread . Потоки, как известно, сложны и подвержены ошибкам, поэтому очень важно четко представлять, как они работают.

Начнем с Javadoc для Thread.sleep :

Приводит к тому, что выполняемый в данный момент поток переходит в спящий режим (временно прекращает выполнение) на указанное количество миллисекунд.

Каковы последствия прекращения выполнения ( cease execution ), также известного как блокировка, и что означает это понятие? Имеет ли оно негативное влияние? И если да, то можно ли обеспечить переход в спящий режим без блокировки?

О чем мы расскажем в этой статье

Данная статья затрагивает много вопросов, и, возможно, вы узнаете много интересного для себя.

  • Что происходит на уровне ОС во время сна?
  • Проблема со спящим режимом.
  • Проект Loom и виртуальные потоки.
  • Функциональное программирование и дизайн.
  • Библиотека ZIO для параллелизма в Scala.
Читайте также:  Где можно починить лобовое стекло

Начнем мы с этого простого фрагмента на Scala, который на протяжении всей статьи будем модифицировать, чтобы достичь цели:

Все довольно просто: программа печатает “a”, а затем через 10 секунд печатает “b”.

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

Как сон работает на уровне ОС?

Вот что происходит “под капотом” при запуске Thread.sleep .

  • Он вызывает потоковый API базовой ОС.
  • Поскольку JVM использует отображение один к одному между потоками Java и ядра, она просит ОС отказаться от “прав” потока на ЦП в течение указанного времени.
  • По истечении этого времени планировщик ОС разбудит поток с помощью прерывания (это эффективно) и назначит ему фрагмент процессора, чтобы он мог возобновить работу.

Критический момент здесь в том, что спящий поток полностью извлекается и во время сна не переиспользуется.

Ограничения потоков

Вот несколько важных ограничений, которые сопутствуют потокам.

  • Ограниченное количество создаваемых потоков. Примерно после тридцати тысяч вы получите такую ошибку:

java.lang.OutOfMemoryError : unable to create new native Thread

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

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

Проблема со спящим режимом

Определим проблему более конкретно: запустим фрагмент кода для наглядности. Чтобы проиллюстрировать суть, воспользуемся следующей функцией.

Вот что делает эта простая функция:

  • печатает start , за которым следует идентификатор потока;
  • уходит в сон на 10 секунд;
  • печатает end , за которым следует идентификатор потока.

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

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

Готовы ли вы принять этот вызов?

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

1 задача -> 1 поток

Запустим jvisualvm , чтобы проверить, что делает поток:

Как видно, нулевой поток (Thread-0) находится в фиолетовом (спящем) состоянии.

Нажатие кнопки “Thread Dump” выведет следующее:

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

2 задачи -> 1 поток

Проиллюстрируем эту проблему, запустив уже две такие задачи только с одним доступным потоком:

Получим следующий вывод:

Как видите, для pool-1-thread-1 отображается фиолетовый цвет (состояние сна). У задач нет другого выбора, кроме как запускаться последовательно, потому что поток выводится из употребления каждый раз, когда задействуется Thread.sleep .

2 задачи -> 2 потока

Запустим тот же самый код при двух доступных потоках. Получим следующее:

Каждый поток может выполнять по одной задаче за раз. В конце концов мы достигли того, чего хотели, выполнив одновременно две задачи, и вся программа закончилась за 10 секунд.

Это было легко, потому что мы воспользовались двумя потоками ( pool-1-thread-1 и pool-1-thread-2 ), но нам хотелось бы сделать то же самое с одним.

Проблема зафиксирована. Теперь поищем решение.

Проблема: Thread.sleep is blocking

Теперь мы понимаем, что не можем пользоваться Thread. sleep — он блокирует поток. Это делает его непригодным к работе до тех пор, пока он не возобновится, и не дает выполнять больше одной задачи одновременно.

К счастью, есть решения, о которых мы поговорим далее.

Первое решение: обновите JVM с помощью Project Loom

Выше уже говорилось, что потоки JVM сопоставляются один к одному с потоками ОС. И эта роковая ошибка дизайна приводит нас сюда.

Project Loom стремится исправить это, добавив виртуальные потоки.

Вот наш код, переписанный с участием виртуальных потоков от Loom:

Самое удивительное, что Thread. sleep больше ничего не блокирует! Он полностью асинхронен. И вдобавок ко всему, виртуальные потоки очень дешевы. Вы можете создавать их сотнями тысяч без каких-либо накладных расходов или ограничений.

Все наши проблемы теперь решены. Кроме того, что Project Loom не будет доступен по крайней мере до выпуска JDK 17 (во время написания статьи запланирован на сентябрь 2021 года).

Читайте также:  Не работают электрозеркала ларгус

Вернемся назад и попробуем выйти из затруднения с текущими возможностями JVM.

Ключевая идея: вы можете выразить сон в терминах планирования задачи на будущее

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

Со стороны эквивалентно этому:

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

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

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

Недостатки планирования

К счастью, планировать задачи несложно. Просто нужно сменить исполнителя:

val oneThreadScheduleExecutor = Executors.newScheduledThreadPool(1)

Теперь вместо функции execute можно воспользоваться функцией shedule :

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

Получилось. Единственный поток и две параллельные задачи, которые “спят” по десять секунд каждая.

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

Нужно будет изменить реализацию nonBlockingTask и добавить туда еще один вызов schedule . И всё быстро станет очень запутанным.

Как написать DSL с неблокирующим сном при помощи функционального программирования

Функциональное программирование на Scala — одно удовольствие, а писать DSL (доменно-специфичный язык) с использованием принципов ФП довольно просто.

Начнем с конца. Нам нужно, чтобы окончательная версия программы выглядела примерно так:

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

Модель

Определим типы данных:

В функциональном программировании типы данных содержат только данные и никакого поведения. Таким образом, весь этот код “ничего не делает” — он просто фиксирует структуру языка и необходимую информацию.

Воспользуемся двумя функциями:

  • sleep для перевода задачи в спящий режим.
  • andThen для сцепления задач.

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

Теперь воспользуемся функцией nonBlockingFunctionalTask :

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

Если мы выведем результат в REPL, то получим следующее:

Напишем интерпретатор, который превратит это дерево в элемент, который будет выполнять задачи.

Интерпретатор

В ФП функция, которая превращает описание в исполняемую программу, называется интерпретатором ( interpreter ). Он берет описание программы, ее модель и интерпретирует в исполняемую форму. Здесь он будет выполнять и планировать задачи напрямую.

Для начала нам понадобится стек, который позволит кодировать зависимости между задачами. Каждый start >>= middle >>= end будет помещаться в стек, а затем выскакивать в порядке выполнения. Это будет видно при реализации.

Теперь переходим к интерпретатору. Не волнуйтесь, если не понимаете этот код. Он довольно сложный, но есть и более простое решение.

И вывод получается точно таким, как и ожидалось:

Один поток выполняет две параллельные “спящие” задачи. За этим стоит много кода и много работы. Как обычно в таких ситуациях, надо спросить себя: есть ли библиотека, которая уже решает эту проблему. Оказывается, есть, и это ZIO.

Сон без блокировки в ZIO

ZIO — это функциональная библиотека для асинхронного и параллельного программирования. Принцип ее работы схож с нашим маленьким DSL: она предоставляет несколько типов, которые можно смешивать и сопоставлять, чтобы описать свою программу. Затем она снабжает нас интерпретатором, который позволяет запускать ZIO-программу.

Как уже упоминалось, паттерн интерпретатора широко распространен в ФП. Как только вы его освоите, перед вами откроется новый мир.

ZIO.sleep — улучшенный вариант Thread.sleep

ZIO предоставляет функцию ZIO.sleep , неблокирующую версию Thread.sleep . Вот наша функция, написанная с помощью ZIO:

Это поразительно похоже на первый фрагмент:

Ключевое различие заключается в синтаксисе for , который позволяет связывать операторы с типом ZIO. Это очень похоже на функцию andThen из рассмотренного ранее мини-языка.

Как и прежде в случае с мини-языком, эта программа — просто описание. Это чистая информация, и она ничего не делает. Чтобы что-то сделать, нужен интерпретатор.

Интерпретатор ZIO

Чтобы интерпретировать ZIO-программу, нужно просто расширить интерфейс ZIO.App и поместить его в метод run , а ZIO возьмет на себя запуск. Примерно так:

И получаем результат — задачи корректно выполняются за десять секунд:

Источник

Оцените статью