Как выполнение трудоемких операций в основном потоке влияет на обновление пользовательского интерфейса - PullRequest
1 голос
/ 21 мая 2019

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

  1. Код обновления представления, ожидающий завершения трудоемкой операции, прежде чем она может быть выполнена, причинаПользовательский интерфейс не работает?

    [NSThread detachNewThreadSelector:@selector(syncMain) toTarget:self withObject:nil];
    - (void)syncMain {
        dispatch_queue_t queue = dispatch_get_main_queue();
    
        dispatch_sync(queue, ^{
            // 追加任务1
            for (int i = 0; i < 2; ++i) {
                [NSThread sleepForTimeInterval:2];   // Simulated time-consuming operation
                NSLog(@"1---%@",[NSThread currentThread]);      // on the main thread
            }
        });
        self.testImage=[UIImage imageNamed:xxx];//Waiting for a time-consuming operation to complete, causing a UI refresh block
    }
    
  2. Влияет ли выполнение асинхронных длительных операций в основном потоке на текучесть пользовательского интерфейса?

    - (void)asyncMain {    
        dispatch_queue_t queue = dispatch_get_main_queue();
    
        dispatch_async(queue, ^{
            // 追加任务1
            for (int i = 0; i < 2; ++i) {
                [NSThread sleepForTimeInterval:2]; // Simulated time-consuming operation
                NSLog(@"1---%@",[NSThread currentThread]);      // on the main thread,too
            }
        });
    
        self.testImage=[UIImage imageNamed:xxx];//Execute code now
    }
    
  3. Трудоемкие операции могут выполняться асинхронно только в дочерних потоках для сохранения целостности пользовательского интерфейса?

    - (void)asyncChild {    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                       [NSThread sleepForTimeInterval:2]; // Simulated time-consuming operation
                    dispatch_async(dispatch_get_main_queue(), ^{
                    self.testImage=[UIImage imageNamed:xxx];
                        });
                });
    }
    

Ответы [ 3 ]

0 голосов
/ 21 мая 2019

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

0 голосов
/ 21 мая 2019

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

Если вы видите отставание, это может произойти, если:

  • фоновый поток случайно выполнил некотороеОбновление пользовательского интерфейса, игнорируя отправку этого обратно в основной поток;

  • фоновое задание отправило несколько каскадных серий задач в параллельные глобальные очереди, исчерпав очень ограниченные доступные рабочие потоки;

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

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


В вашем редакторе вы приводите несколько примеров:

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

    [NSThread detachNewThreadSelector:@selector(syncMain) toTarget:self withObject:nil];
    
    - (void)syncMain {
        dispatch_queue_t queue = dispatch_get_main_queue();
    
        dispatch_sync(queue, ^{
            // 追加任务1
            for (int i = 0; i < 2; ++i) {
                [NSThread sleepForTimeInterval:2];   // Simulated time-consuming operation
                NSLog(@"1---%@",[NSThread currentThread]);      // on the main thread
            }
        });
        self.testImage=[UIImage imageNamed:xxx];//Waiting for a time-consuming operation to complete, causing a UI refresh block
    }
    

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

[NSThread detachNewThreadSelector:@selector(asyncMain) toTarget:self withObject:nil];

- (void)asyncMain {    
    dispatch_queue_t queue = dispatch_get_main_queue();

    for (int i = 0; i < 2; ++i) {
        [NSThread sleepForTimeInterval:2]; // Simulated time-consuming operation
        NSLog(@"1---%@",[NSThread currentThread]);      // still on the background thread
    }

    dispatch_async(queue, ^{            
        self.testImage=[UIImage imageNamed:xxx];//Execute code now
    });
}

И нет причин синхронно отправлять обновления обратно в основную очередь.Отправляйте эти обновления асинхронно. Почему фоновый поток ожидает завершения обновления пользовательского интерфейса?

Лично я бы предложил исключить detachNewThreadSelector и просто придерживаться GCD (как в третьем примере):

- (void)someTaskAndUpdateUI {    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2]; // Simulated time-consuming operation
            NSLog(@"1---%@",[NSThread currentThread]); // but on background queue
        }

        dispatch_async(dispatch_get_main_queue(), ^{            
            self.testImage=[UIImage imageNamed:xxx];//Execute code now
        });
    });
}

Влияет ли выполнение асинхронных длительных операций в главном потоке на текучесть пользовательского интерфейса?

- (void)asyncMain {    
    dispatch_queue_t queue = dispatch_get_main_queue();

    dispatch_async(queue, ^{
        // 追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2]; // Simulated time-consuming operation
            NSLog(@"1---%@",[NSThread currentThread]);      // on the main thread,too
        }
    });

    self.testImage=[UIImage imageNamed:xxx];//Execute code now
}

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

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

Могут ли трудоемкие операции выполняться только в дочерних потоках асинхронно, чтобы сохранить целостность интерфейса?

- (void)asyncChild {    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [NSThread sleepForTimeInterval:2]; // Simulated time-consuming operation
        dispatch_async(dispatch_get_main_queue(), ^{
            self.testImage=[UIImage imageNamed:xxx];
        });
    });
}

Исправить.И я бы посоветовал вам использовать этот третий шаблон и полностью исключить detachNewThreadSelector из вашего кода.Палка с GCD.

0 голосов
/ 21 мая 2019

Можете ли вы привести пример некоторых операций, с которыми у вас возникли проблемы?

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

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

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