Grand Central Dispatch vs NSOperation

465

Estou aprendendo sobre programação simultânea para iOS. Até agora eu li sobre NSOperation/NSOperationQueue e GCD. Quais são as razões para usar NSOperationQueuerepetidamente GCDe vice-versa?

Soa como ambos GCDe NSOperationQueueabstrai a criação explícita NSThreadsdo usuário. No entanto, a relação entre as duas abordagens não está clara para mim, portanto qualquer feedback deve ser apreciado!

Domingo segunda-feira
fonte
10
+1 para uma boa pergunta - curioso sobre os resultados. Até agora, acabei de ler que o GCD pode ser facilmente despachado pelos núcleos da CPU, tornando-a a "nova merda".
Até
3
Algumas discussões relacionadas podem ser encontradas nesta pergunta: Por que devo escolher o GCD em vez de NSOperation e blocos para aplicativos de alto nível?
Brad Larson

Respostas:

517

GCDé uma API baseada em C de baixo nível que permite o uso muito simples de um modelo de simultaneidade baseado em tarefas. NSOperatione NSOperationQueuesão classes Objective-C que fazem uma coisa semelhante. NSOperationfoi introduzido primeiro, mas a partir do 10.5 e iOS 2 , NSOperationQueuee os amigos são implementados internamente usando GCD.

Em geral, você deve usar o nível mais alto de abstração que atenda às suas necessidades. Isso significa que você geralmente deve usar em NSOperationQueuevez de GCD, a menos que precise fazer algo que NSOperationQueuenão é compatível.

Observe que NSOperationQueuenão é uma versão "simplificada" do GCD; de fato, há muitas coisas que você pode fazer com muita simplicidade e NSOperationQueueque exigem muito trabalho com pura GCD. (Exemplos: filas com restrição de largura de banda que executam apenas operações N de cada vez; estabelecendo dependências entre operações. Muito simples com NSOperation, muito difícil com GCD.) A Apple fez o trabalho duro de alavancar o GCD para criar uma API agradável e amigável para objetos NSOperation. Aproveite o trabalho deles, a menos que você tenha um motivo para não fazê-lo.

Advertência : Por outro lado, se você realmente precisa enviar um bloco e não precisa de nenhuma das funcionalidades adicionais que NSOperationQueuefornecem, não há nada de errado em usar o GCD. Apenas certifique-se de que é a ferramenta certa para o trabalho.

BJ Homer
fonte
1
NSOperation para especificar uma classe abstrata.
21414 Roshan
3
@ Sandy Na verdade, é o contrário, o GCD é usado pelo NSOperation (pelo menos nas versões posteriores do iOS e OS X).
garrettmoon
1
@BJ Homer Podemos adicionar tarefas na fila de expedição serial para obter aparência. assim justfy como operação de fila têm vantagem sobre os que
Raj Aggrawal
3
@RajAggrawal Sim, isso funciona ... mas você está preso a uma fila serial. O NSOperation pode "executar esta operação depois que as outras três estiverem concluídas, mas simultaneamente com todas as outras coisas acontecendo". Dependências de operação podem até existir entre operações em diferentes filas. A maioria das pessoas não precisa disso, mas se você precisar, a NSOperation seria uma escolha melhor.
BJ Homer
369

De acordo com a minha resposta a uma pergunta relacionada , vou discordar de BJ e sugerir que você examine primeiro o GCD sobre NSOperation / NSOperationQueue, a menos que este último forneça algo que o GCD não precisa.

Antes do GCD, eu usava muitos NSOperations / NSOperationQueues em meus aplicativos para gerenciar a simultaneidade. No entanto, desde que comecei a usar o GCD regularmente, substituí quase completamente o NSOperations e o NSOperationQueues por blocos e filas de despacho. Isso veio da maneira como utilizei as duas tecnologias na prática e do perfil que realizei nelas.

Primeiro, há uma quantidade não trivial de sobrecarga ao usar NSOperations e NSOperationQueues. Esses são objetos de cacau e precisam ser alocados e desalocados. Em um aplicativo iOS que escrevi que renderiza uma cena 3D a 60 FPS, eu estava usando NSOperations para encapsular cada quadro renderizado. Quando criei um perfil disso, a criação e o detalhamento dessas operações de NSO foram responsáveis ​​por uma parte significativa dos ciclos da CPU no aplicativo em execução e estavam atrasando as coisas. Substituí-os por blocos simples e uma fila serial do GCD, e essa sobrecarga desapareceu, levando a um desempenho notavelmente melhor na renderização. Este não foi o único lugar em que notei sobrecarga ao usar NSOperations, e já vi isso no Mac e no iOS.

Segundo, há uma elegância ao código de despacho baseado em bloco que é difícil de combinar ao usar o NSOperations. É incrivelmente conveniente agrupar algumas linhas de código em um bloco e enviá-lo para uma fila serial ou simultânea, onde a criação de um NSOperation ou NSInvocationOperation personalizado para fazer isso exige muito mais código de suporte. Eu sei que você pode usar um NSBlockOperation, mas também pode estar enviando algo para o GCD. Embrulhar esse código em blocos alinhados com o processamento relacionado em seu aplicativo leva, em minha opinião, a uma melhor organização de código do que ter métodos separados ou NSOperations personalizadas que encapsulam essas tarefas.

NSOperations e NSOperationQueues ainda têm usos muito bons. O GCD não tem um conceito real de dependências, onde NSOperationQueues pode configurar gráficos de dependência bastante complexos. Eu uso NSOperationQueues para isso em alguns casos.

No geral, embora eu costumo advogar o uso do mais alto nível de abstração que realiza a tarefa, este é um caso em que defendo a API de nível mais baixo da GCD. Entre os desenvolvedores de iOS e Mac com quem conversamos sobre isso, a grande maioria escolhe usar o GCD em vez de NSOperations, a menos que eles tenham como alvo versões de SO sem suporte para ele (antes do iOS 4.0 e do Snow Leopard).

Brad Larson
fonte
20
Eu apenas discordo levemente; Eu uso bastante o GCD. Mas acho que você desconsidera muito o NSBlockOperation nesta resposta. Todos os benefícios do NSOperationQueue (dependências, depuração etc.) também se aplicam às operações de bloqueio.
BJ Homer
4
@BJHomer - Eu acho que evitar o NSBlockOperation é mais uma questão de preferência pessoal no meu caso, embora eu tenha evitado as NSOperations em geral depois de ver a sobrecarga de seu uso arrastar algumas aplicações. Se vou usar blocos, costumo usar o GCD, com a rara exceção de quando preciso de suporte a dependências.
Brad Larson
1
+1, obrigado por esta análise. A Apple parece defender ambos (como a sessão da WWDC 2012 na interface do usuário simultânea), então isso é muito apreciado.
orip 24/07/12
1
@VolureDarkAngel - O GCD é extremamente rápido ao lidar com despachos como esse. Não deve ser o seu gargalo em uma situação como você descreve, a menos que você faça backup de uma pilha de atualizações em uma fila devido a acessos lentos de E / S ou algo do tipo. Provavelmente não é o caso aqui.
Brad Larson
1
@ asma22 - É comum ter cálculos que podem ser feitos em blocos, mas o cálculo final de um estágio pode precisar dos resultados de vários estágios anteriores. Nesse caso, você pode fazer com que a operação posterior dependa das operações anteriores, e o planejamento será gerenciado de forma que todos sejam concluídos antes da execução da última.
Brad Larson
101

GCDé uma API baseada em C de baixo nível.
NSOperatione NSOperationQueuesão classes Objective-C.
NSOperationQueueé o wrapper C objetivo GCD. Se você estiver usando o NSOperation, estará implicitamente usando o Grand Central Dispatch.

Vantagem de GCD sobre NSOperation:
i. implementação
Para GCDimplementação é muito leve
NSOperationQueueé complexo e pesado

Vantagens de NSOperation sobre GCD:

Eu. Controle Na operação,
você pode pausar, cancelar, retomar umaNSOperation

ii. Dependências que
você pode configurar uma dependência entre duas NSOperations
operações não serão iniciadas até que todas as suas dependências retornem verdadeiras para concluídas.

iii. State of Operation
pode monitorar o estado de uma operação ou fila de operações. pronto, executando ou finalizado

iv. Número máximo de operações,
você pode especificar o número máximo de operações na fila que podem ser executadas simultaneamente

Quando procurar GCDouNSOperation
quando desejar mais controle sobre o uso da fila (todos mencionados acima) NSOperation e para casos simples em que você deseja menos custos indiretos (você só quer fazer algum trabalho "em segundo plano" com muito pouco trabalho adicional)GCD

ref:
https://cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch/ http://iosinfopot.blogspot.in/2015/08/nsthread-vs-gcd-vs-nsoperationqueue.html http : //nshipster.com/nsoperation/

Sangram Shivankar
fonte
Como dito, o número máximo de operações pode ser especificado em NSOperationQueue. Então, qual pode ser o número máximo de operações (filas de despacho) no GCD? Suponha que eu tenha um projeto. Quantas operações (filas de despacho) posso executar. ou os limites máximos deles até o que podemos fazer.
Roshan Sah
Depende das condições do sistema aqui é os detalhes: stackoverflow.com/questions/14995801/...
Sangram Shivankar
Podemos cancelar tarefa na GCD também usando DispatchWorkItem e podemos suspender e retomar também
Ankit garg
O cancelamento da chamada @Ankitgarg no DispatchWorkItem interromperá a execução de tarefas se ainda não tiverem sido executadas, mas não interromperá algo que já esteja em execução. e como você pausa / retoma um DispatchWorkItem ??
abhimuralidharan
34

Outro motivo para preferir a NSOperation ao GCD é o mecanismo de cancelamento da NSOperation. Por exemplo, um aplicativo como 500px que mostra dezenas de fotos, use NSOperation, podemos cancelar solicitações de células de imagem invisíveis ao rolar a exibição de tabela ou exibição de coleção, isso pode melhorar muito o desempenho do aplicativo e reduzir o consumo de memória. O GCD não pode suportar isso facilmente.

Também com NSOperation, o KVO pode ser possível.

Aqui está um artigo de Eschaton que vale a pena ler.

evanchin
fonte
4
Vale a pena notar que, se o que você está cancelando é a operação da rede de carregar a imagem, então você não precisa NSOperationpara isso, como NSURLSessionTask.cancele NSURLSession.invalidateAndCancelfornecer essa funcionalidade. Em geral, NSURLSessionproporciona algumas das funcionalidades de um NSOperationQueue, como NSURLSessionTaskfornece alguma da funcionalidade de umNSOperation
de algas
@algal Conforme explicado aqui ( stackoverflow.com/questions/21918722/… ), parece que o NSURLSession usa NSOperationQueue como um bloco de construção.
kalan nawarathne
33

O GCD é realmente de nível inferior ao NSOperationQueue, sua principal vantagem é que sua implementação é muito leve e focada em algoritmos e desempenho sem bloqueios.

O NSOperationQueue fornece recursos que não estão disponíveis no GCD, mas eles têm um custo não trivial, a implementação do NSOperationQueue é complexa e pesada, envolve muito bloqueio e usa o GCD internamente apenas de uma maneira muito mínima.

Se você precisar dos recursos fornecidos pelo NSOperationQueue, use-o de qualquer maneira, mas se o GCD for suficiente para suas necessidades, eu recomendaria usá-lo diretamente para obter melhor desempenho, reduzir significativamente o custo de CPU e energia e mais flexibilidade.

das
fonte
24

O NSQueueOperations e o GCD permitem executar tarefas de computação pesada em segundo plano em threads separados, liberando o passo principal do aplicativo de interface do usuário.

Bem, com base na postagem anterior, vemos que o NSOperations tem addDependency para que você possa enfileirar sua operação uma após a outra sequencialmente.

Mas também li sobre as filas seriais do GCD que você pode criar para executar suas operações na fila usando dispatch_queue_create. Isso permitirá executar um conjunto de operações, uma após a outra, de maneira seqüencial.

Vantagens do NSQueueOperation sobre o GCD:

  1. Ele permite adicionar dependência e remover a dependência para que, em uma transação, você possa executar sequencialmente usando dependência e em outras transações simultaneamente, enquanto o GCD não permite executar dessa maneira.

  2. É fácil cancelar uma operação se estiver na fila e pode ser interrompida se estiver em execução.

  3. Você pode definir o número máximo de operações simultâneas.

  4. Você pode suspender a operação em que estão na fila

  5. Você pode encontrar quantas operações pendentes existem na fila.

Shashi3456643
fonte
6

O GCD é muito fácil de usar - se você deseja fazer algo em segundo plano, basta escrever o código e enviá-lo para uma fila de segundo plano. Fazer o mesmo com o NSOperation é muito trabalho adicional.

A vantagem do NSOperation é que (a) você tem um objeto real para o qual pode enviar mensagens e (b) que pode cancelar um NSOperation. Isso não é trivial. Você precisa subclassificar NSOperation, precisa escrever seu código corretamente para que o cancelamento e o término correto de uma tarefa funcionem corretamente. Portanto, para coisas simples, você usa o GCD e, para coisas mais complicadas, cria uma subclasse de NSOperation. (Existem subclasses NSInvocationOperation e NSBlockOperation, mas tudo o que fazem é mais fácil com o GCD, portanto, não há um bom motivo para usá-las).

gnasher729
fonte
3

Bem, as NSOperations são simplesmente uma API criada sobre o Grand Central Dispatch. Então, quando você estiver usando NSOperations, ainda estará usando o Grand Central Dispatch. É que as NSOperations oferecem alguns recursos interessantes que você pode gostar. Você pode tornar algumas operações dependentes de outras operações, reordenar filas depois de suprimir itens e outras coisas assim. De fato, o ImageGrabber já está usando NSOperations e filas de operações! O ASIHTTPRequest os utiliza sob o capô, e você pode configurar a fila de operações que ele usa para um comportamento diferente, se desejar. Então, qual você deve usar? O que fizer sentido para o seu aplicativo. Para este aplicativo, é bastante simples, então usamos o Grand Central Dispatch diretamente, sem a necessidade dos recursos sofisticados do NSOperation. Mas se você precisar deles para o seu aplicativo, fique à vontade para usá-lo!

Ankul Gaur
fonte