Почему это нить.Спать так вредно
Я часто вижу, что он упомянул, что Thread.Sleep(); не следует использовать, но я не могу понять, почему это так. Если Thread.Sleep(); может вызвать проблемы, есть ли альтернативные решения с тем же результатом, который был бы безопасным?
например.
while(true)
{
doSomework();
i++;
Thread.Sleep(5000);
}
другое:
while (true)
{
string[] images = Directory.GetFiles(@"C:Dir", "*.png");
foreach (string image in images)
{
this.Invoke(() => this.Enabled = true);
pictureBox1.Image = new Bitmap(image);
Thread.Sleep(1000);
}
}
7 ответов:
проблемы с вызовом
Thread.Sleepare объяснил довольно лаконично здесь:
Thread.Sleepимеет свое использование: имитация длительных операций при тестировании / отладке в потоке MTA. В .Чистый нет никаких других причин, чтобы использовать его.
Thread.Sleep(n)означает блокировать текущий поток по крайней мере на число временных интервалов (или квантов потоков), которые могут происходить в пределахnмиллисекунды. Длина ввода-вывода отличается на разных варианты / типы Windows и разные процессоры и вообще колеблется от 15 до 30 миллисекунды. Это означает, что поток почти гарантированно блокируется для больше чемnмиллисекундах. Вероятность того, что ваш поток будет просыпайтесь ровно послеnмиллисекунд примерно так же невозможно, как невозможно может быть. иThread.Sleepбессмысленно по времени.потоки являются ограниченным ресурсом, они занимают около 200 000 циклов создавать и около 100 000 циклов для уничтожения. По умолчанию они резерв 1 мегабайт виртуальной памяти для стека и использовать 2,000-8,000 циклы для каждого переключения контекста. это делает любой ожидающий поток a огромный отходов.
предпочтительное решение: WaitHandles
самая большая ошибка-это использование
Thread.Sleepс помощью while-construct (демо и ответа,Ницца блог-запись)EDIT:
Я хотел бы улучшить свой ответ:у нас есть 2 разных варианта использования:
мы ждем, потому что мы знаем конкретный промежуток времени, когда мы должны продолжить (использовать
Thread.Sleep,System.Threading.Timerили alikes)мы ждем, потому что некоторые условия меняются некоторое время ... ключевое слово(ы) is/are времени! если условие-проверка в нашем коде-домене, мы следует использовать WaitHandles-в противном случае внешний компонент должен предоставить какие-то крючки ... если это не его дизайн плохо!
мой ответ в основном охватывает use-case 2
сценарий 1-ожидание завершения асинхронной задачи: я согласен, что WaitHandle/Auto|ManualResetEvent следует использовать в сценарии, где поток ожидает завершения задачи в другом потоке.
сценарий 2-синхронизация в то время как цикл: однако, как нефть механизм синхронизации (в то время как + поток.Sleep) отлично подходит для 99% приложений, которые не требуют знания ровно когда заблокированный поток должен " проснуться*. Аргумент, что для этого требуется 200k циклов создание потока также недопустимо - поток цикла синхронизации должен быть создан в любом случае, а циклы 200k-это еще одно большое число (скажите мне, сколько циклов для открытия вызовов file/socket/db?).
Так что если при+нить.Сон работает, зачем все усложнять? Только синтаксис юристы бы, быть практические!
Я хотел бы ответить на этот вопрос с точки зрения кодирования-политики, которая может быть или не быть полезной никому. Но особенно когда вы имеете дело с инструментами, которые предназначены для 9-5 корпоративных программистов, люди, которые пишут документацию, как правило, используют такие слова, как "не следует" и "никогда", чтобы означать "не делайте этого, если вы действительно не знаете, что вы делаете и почему".
несколько моих других фаворитов в мире C# - это то, что они говорят вам "никогда не звоните lock(this)" или - никогда не звони в ГК.Собирать.")( Эти два решительно объявлены во многих блогах и официальной документации, и Имо являются полной дезинформацией. На каком-то уровне эта дезинформация служит своей цели, поскольку она удерживает новичков от того, чтобы делать то, что они не понимают, прежде чем полностью исследовать альтернативы, но в то же время это затрудняет поиск реальной информации через поисковые системы, которые все, кажется, указывают на статьи, говорящие вам не делать что-то, не предлагая ответа на этот вопрос вопрос "почему бы и нет?"
политически это сводится к тому, что люди считают "хорошим дизайном" или "плохим дизайном". Официальная документация не должна диктовать дизайн моего заявления. Если есть действительно техническая причина, по которой вы не должны вызывать sleep (), то в документации IMO должно быть указано, что это совершенно нормально называть его по определенным сценариям, но, возможно, предложить некоторые альтернативные решения, которые являются независимыми от сценария или более подходящими для других сценариев.
явный вызов "sleep ()" полезен во многих ситуациях, когда сроки четко определены в терминах реального времени, однако существуют более сложные системы для ожидания и сигнализации потоков, которые следует рассмотреть и понять, прежде чем вы начнете бросать sleep () в свой код, а бросание ненужных операторов sleep () в вашем коде обычно считается тактикой новичков.
это 1).спиннинг и 2).цикл опроса ваших примеров, которые люди предостерегают от, а не нить.Сон() часть. Я думаю, что нить.Sleep () обычно добавляется для легкого улучшения кода, который вращается или находится в цикле опроса, поэтому он просто связан с "плохим" кодом.
кроме того, люди делают такие вещи, как:
while(inWait)Thread.Sleep(5000);где переменная inWait не доступна потокобезопасным способом, что также вызывает проблемы.
что программисты хотите видеть, что потоки управляются событиями и сигнализацией и блокировкой конструкций, и когда вы это сделаете, вам не понадобится поток.Sleep (), а также устраняются проблемы с потокобезопасным доступом к переменным. Например, можно ли создать обработчик событий, связанный с классом FileSystemWatcher, и использовать событие для запуска второго примера вместо цикла?
Как упоминал Андреас Н., читайте Threading in C#, by Joe Albahari, это действительно реально хороший.
Sleep используется в тех случаях, когда независимая программа(ы), которую вы не контролируете, иногда может использовать обычно используемый ресурс (например, файл), к которому ваша программа должна получить доступ при запуске, и когда ресурс используется этими другими программами, ваша программа блокируется от его использования. В этом случае, когда вы получаете доступ к ресурсу в своем коде, вы помещаете свой доступ к ресурсу в try-catch (чтобы поймать исключение, когда вы не можете получить доступ к ресурсу), и вы помещаете это в цикл while. Если ресурс свободен, сон никогда не вызывается. Но если ресурс заблокирован, то вы спите в течение соответствующего времени и пытаетесь снова получить доступ к ресурсу (поэтому вы зацикливаетесь). Однако, имейте в виду, что вы должны поставить какой-то ограничитель на петлю, так что это не потенциально бесконечный цикл. Вы можете установить свое предельное условие в N количество попыток (это то, что я обычно использую), или проверить системные часы, добавить фиксированное количество времени, чтобы получить ограничение по времени, и выйти попытка доступа, если вы нажмете ограничение по времени.
Я согласен со многими здесь, но я также думаю, что это зависит.
недавно я сделал этот код:
private void animate(FlowLayoutPanel element, int start, int end) { bool asc = end > start; element.Show(); while (start != end) { start += asc ? 1 : -1; element.Height = start; Thread.Sleep(1); } if (!asc) { element.Hide(); } element.Focus(); }это была простая анимационная функция, и я использовал
Thread.Sleepна нем.мой вывод, если он работает, используйте его.
для тех из вас, кто не видел ни одного действительного аргумента против использования потока.Сон в сценарии 2, действительно есть выход из одного приложения, который будет удерживаться циклом while (Сценарий 1/3 просто глупо, так что не стоит больше упоминать)
многие, кто притворяется, что в курсе, кричат нить.Сон-это зло не упомянул ни одной уважительной причины для тех из нас, кто требовал практической причины не использовать его - но вот он, благодаря Питу -нить.Сон Зло (можно легко избежать с помощью таймера / обработчика)
static void Main(string[] args) { Thread t = new Thread(new ThreadStart(ThreadFunc)); t.Start(); Console.WriteLine("Hit any key to exit."); Console.ReadLine(); Console.WriteLine("App exiting"); return; } static void ThreadFunc() { int i=0; try { while (true) { Console.WriteLine(Thread.CurrentThread.ThreadState.ToString() + " " + i); Thread.Sleep(1000 * 10); i++; } } finally { Console.WriteLine("Exiting while loop"); } return; }
Comments