NSTimer иногда зависает, когда приложение выполняет тяжелые вычисления - PullRequest
1 голос
/ 09 января 2012

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

    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.3f
                                             target:self 
                                           selector:@selector(updateLoadingPoints:) 
                                           userInfo:nil 
                                            repeats:YES];

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

Есть ли способ дать NSTimer более высокий приоритет, чтобы он регулярно вызывал мой метод? Или есть другой способ добиться этого?

Ответы [ 4 ]

3 голосов
/ 09 января 2012

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

Из-за того, как они реализованы, невозможно повысить приоритет таймера.

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

Вызов performSelectorOnMainThread: не обязательно поможет, потому что эти методы по существу добавляют таймер одиночного запуска в очередь событий основного потока. Так что вы просто будете устанавливать таймеры по-другому.

Чтобы исправить вашу проблему, я бы посоветовал вам увеличить относительный приоритет основного потока на , уменьшив приоритет вашего вычислительного потока . (См. [NSThread setThreadPriority:].)

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

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

0 голосов
/ 10 января 2012

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

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

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

0 голосов
/ 09 января 2012

Выполните ваши вычисления в отдельном потоке, используя executeSelectorInBackground: withObject. Всегда выполняйте как можно меньше в цикле пользовательского интерфейса, поскольку любая выполняемая здесь работа будет предотвращать щелчки мышью, вызывать SPoDs / beachballs и задерживать обработчики таймера.

Я подозреваю, что не только ваш ТАЙМЕР не отвечает, но и весь пользовательский интерфейс в целом.

Извините, что вызвал неправильный API в моей предыдущей ревизии - ошибка копирования / вставки с моей стороны.

0 голосов
/ 09 января 2012

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

...