С# — альтернатива Thread.Sleep?

Я делаю все это на C#, в Visual Studio 2008.

Я хочу замедлить работу своего алгоритма, чтобы пользователь мог наблюдать за его работой. В графическом интерфейсе видны периодические изменения, поэтому я добавил «thread.sleep» после каждого экземпляра.

Проблема в том, что «thread.sleep», если установлено как минимум на секунду, после нескольких экземпляров «thread.sleep» (после нескольких циклов) просто замораживает весь графический интерфейс и сохраняет его таким до завершения программы. Не сразу, но всегда бывает. Как скоро, зависит от продолжительности сна.

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

Как решить эту проблему? Альтернатива алгоритму паузы в определенный момент?


person Edmund    schedule 27.03.2011    source источник
comment
Если вы разместите соответствующий код, вам будет легче помочь.   -  person ahsteele    schedule 27.03.2011
comment
попробуй покопаться в многопоточности Эдмунд   -  person Waqas Raja    schedule 27.03.2011
comment
Нет подходящего фрагмента кода для публикации, кроме всего кода. Я просто использую: Thread.Sleep(1000); когда я хочу 1 секунду паузы.   -  person Edmund    schedule 27.03.2011
comment
Посмотрите этот пост bytes.com/topic/c-sharp/ ответы/687041-альтернативный-поток-сна   -  person Bala R    schedule 27.03.2011
comment
Я полагаю, вы захотите изучить DoEvents() msdn.microsoft.com/en-us/library/   -  person Hogan    schedule 27.03.2011
comment
@Hogan DoEvents? Бу. шипение Однако не так много пользы, когда активен сон.   -  person David Heffernan    schedule 27.03.2011
comment
Дубликат   -  person Sanjeevakumar Hiremath    schedule 27.03.2011
comment
Эдмунд, вы должны выполнять свои вычисления в отдельном потоке, позволяя пользовательскому интерфейсу иметь основной поток. Это винформс? Затем рабочий поток сообщает о статусе обратно в поток пользовательского интерфейса, который не будет спать.   -  person Mikael Svenson    schedule 27.03.2011
comment
Я только что ответил на этот вопрос. Вместо этого вы хотите использовать Timer. Не используйте DoEvents; это не правильный ответ ни на один вопрос.   -  person Cody Gray    schedule 27.03.2011


Ответы (4)


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

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

Если вы хотите это сделать (пожалуйста, не делайте этого), просто создайте Таймер когда вы начинаете выполнять работу, когда она Ticks , указывает на то, что пора перестать притворяться, что выполняете работу.

Еще раз, пожалуйста, не делайте этого.

person Community    schedule 27.03.2011
comment
Согласованный. И если вы действительно хотите, чтобы пользователь мог смотреть, по крайней мере, предусмотрите дроссельную заслонку, с помощью которой он сможет вернуть скорость обратно к нормальной, когда ему надоест смотреть (после первого раза). - person Cody Gray; 27.03.2011

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

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

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

person David Heffernan    schedule 27.03.2011
comment
Хороший ответ - я сказал изучить - вы объяснили. - person Hogan; 27.03.2011
comment
@Hogan: я думаю, вы неправильно поняли ответ Дэвида. Он вообще не рекомендует вам изучать DoEvents. На самом деле, он рекомендует вам отвести взгляд в сторону. Это не правильный ответ; это грязный хак для тех, кто изначально использует неправильное решение. DoEvents создаст здесь больше проблем, чем поможет. - person Cody Gray; 27.03.2011
comment
@Hogan Ответ не был переписан. - person David Heffernan; 27.03.2011
comment
@Cody - Понимание того, что делает DoEvents(), объясняет, почему программа OP не работала. Вооружившись этим знанием, редизайн ясен. Я поддерживаю ОП, мне нужно понять DoEvents() и насос сообщений Windows. - person Hogan; 27.03.2011
comment
@Hogan: Нигде в ваших комментариях не упоминается насос сообщений Windows. Я бы дал этому +1. Упоминание DoEvents вызывает хмурый взгляд. Слишком много программистов используют его неправильно (что, как правило, использует его вообще). И мне показалось подозрительным, как будто вы рекомендуете это. Я не пытаюсь вызвать тебя сюда. Я просто замечаю, что DoEvents не является хорошим решением, даже если оно выглядит как быстрое решение. Понимание того, почему возникает проблема, безусловно, является наиболее желательным вариантом, но мой опыт показывает, что указание людям правильного направления не приводит их к цели. - person Cody Gray; 27.03.2011
comment
@Cody - как раз то, что касается моего первого комментария к этому ответу. Мой комментарий по этому вопросу был явно неправомерным. Я бы удалил его со стыда, но я думаю, что получившаяся ветка поучительна. - person Hogan; 27.03.2011

Вы собираетесь допустить некоторые довольно распространенные ляпы пользовательского интерфейса:

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

Вместо:

  • Отображение результатов в гаджете, таком как ListBox, чтобы пользователь мог просматривать результаты в своем темпе.
  • Сохраняйте пользовательский интерфейс интерактивным с помощью потоков
  • Замедлите время в свою пользу с помощью отладчика
person Hans Passant    schedule 27.03.2011
comment
Честно говоря, мы не знаем, что это за приложение. Возможно, дело в том, чтобы увидеть, как работает алгоритм (маловероятно, но возможно). Например, см. boxcar2d.com , весь смысл этого приложения заключается в наблюдении за генетическим алгоритмом в действии. - person Giovanni Galbo; 27.03.2011

Это зависит от многих вещей, поэтому трудно дать конкретный ответ из того, что вы сказали. Тем не менее, вот некоторые вопросы, которые могут иметь значение:

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

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

person Jon Hanna    schedule 27.03.2011