Подтвердить что ты не робот

Каковы различные способы вызова моего метода в отдельном потоке?

У меня есть метод вычисления данных (пусть это будет "myMethod:" ), и я хочу переместить вызов в другой поток, потому что я не хочу блокировать основные функции пользовательского интерфейса. Итак, начал делать некоторые исследования о том, как вызвать мой метод в другом потоке. Насколько я вижу, в настоящее время существует много разных способов сделать это. Вот список:

a) используя чистые потоки (доступные с iOS 2.0):

[NSThread detachNewThreadSelector:@selector(myMethod:) toTarget:self withObject:_myParamsArray];

b), используя простой ярлык (доступный с iOS 2.0). Доступно из унаследованного NSObject, но метод также относится к классу NSThread:

[self performSelectorInBackground:@selector(myMethod:) withObject:_myParamsArray];

c) с использованием нового подхода к очередям Grand Central Dispatch (доступно с iOS 4.0):

dispatch_async(dispatch_get_global_queue(0, 0),
  ^ {
      [self myMethod:_myParamsArray];
    });

d) каким-то образом, используя некоторые классы, такие как NSOperation, NSBlockOperation или NSOperationQueue, хотя и не уверен, как это сделать (пример будет оценен)

В настоящее время я использовал случай "b", но интересуюсь плюсами и минусами и другими связанными с этим предложениями.

UPDATE: e) также нашел другой способ для выполнения подобных потоков - Run loops. Здесь выдержка из apple docs:

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

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

UPDATE2: У меня уже был некоторый опыт работы с NSInvocationOperation и NSOperationQueue и IMHO, это довольно удобно. Согласно документам Apple, GCD и NSOperations являются предпочтительным способом реализации многопоточности. Кроме того, NSOperations работает на GCD, начиная с iOS 4.0. Короче говоря, вы создаете экземпляр NSIvocationOperation (как вызов вашего метода), затем создаете NSOperationQueue и добавляете вызов в очередь. NSOperationQueue достаточно умен, вы можете создать экземпляр нескольких объектов NSIvocationOperation (перенос вызовов методов) и их в NSOperationQueue. Остальное гарантировано. NSOperationQueue определяет, сколько параллельных потоков требуется для выполнения вызовов (NSInvocationOperation) и обрабатывает их для вас. Он может выполнить первый вызов в потоке A, затем второй по потоку B, третий по потоку C и дальше по потоку B, так что вам не о чем беспокоиться. Но если вы хотите, вы можете указать, как максимальные потоки NSOperationQueue могут использовать для выполнения вызовов (например, 1), но я не нуждаюсь в этом. По умолчанию все задачи выполняются иначе, чем основной поток, поэтому очереди операций по умолчанию асинхронны. Кроме того, если вы хотите выполнять вызовы методов (каждая из которых завершена в отдельную NSInvocationOperation) в строгой очереди, то вы можете добавлять зависимости, и поэтому NSOperationQueue будет сохранять порядок вызова метода. Вот пример:

// wrap your method call into NSInvocationOperation object
NSInvocationOperation *currentOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(yourMethodCall) object:nil];

// _sharedOperationQueue is a shared NSOperationQueue 
// get all executing operations from the queue and get the last operation
_lastOperation = [[_sharedOperationQueue operations] lastObject];

// check if _lastOperation is not nil
if (_lastOperation) {

    // if not then add dependency, so the calls would be performed in a queue
    [currentOperation addDependency:_lastOperation];
}

// say - execute my method (operation)
[_sharedOperationQueue addOperation:currentOperation];

_lastOperation = currentOperation; // mark as last operation for adding dependency to the next operation

// the queue will retain invocation operation so you will release
[currentOperation release];

 ..... you can create another NSInvocationOperation and add it to the queue....

Как и для RUNLOOP, иногда вы сталкиваетесь с ними, например, при запуске/планировании таймера или создании соединений NSURL. IMHO, runloop можно сравнить с очередью задач, выполняемых в одном потоке. IMHO runloop - это указатель на поток, который работает как очередь: он имеет задачи, которые могут вызывать события, и они будут помещены в конец очереди в этом потоке. По умолчанию все задачи в вашем приложении выполняются в одной runloop - в одном потоке. Я говорю это указатель, потому что, когда ваше приложение генерирует события, приложение должно знать, где разместить это событие (событие касания или другой обратный вызов делегата) для выполнения. Конечно, вы должны прочитать о runloops для получения более подробной информации, потому что это только мои мысли.

4b9b3361

Ответ 1

Обычно вы предпочитаете подход GCD.

Это проще, когда речь идет о синхронизации/блокировке, чем чистые потоки (NSThread - pthread), и это может быть более точным с точки зрения производительности.

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

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

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

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

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

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

Надеюсь, это поможет вам:)

ИЗМЕНИТЬ

Заметка о performSelectorInBackground: она просто создает новый поток. Таким образом, в принципе нет никакой разницы с подходом NSThread.

РЕДАКТИРОВАТЬ 2

Материал, связанный с NSOperation, немного отличается. В Mac OS X они реализованы с использованием GCD с версии 10.6. Предыдущие версии используют потоки.

В iOS они реализованы только с использованием потоков.

Ссылка

Все это очень хорошо объяснено в Concurrency Руководство по программированию. В нем обсуждаются подходы GCD и потоков, с подробным описанием использования и реализаций.

Если вы еще не прочитали его, вы должны посмотреть.