SlideShare uma empresa Scribd logo
1 de 19
Baixar para ler offline
Introdução ao Grand Central Dispatch
Programação paralela
●   O que é programação paralela?
●   Por que se preocupar com programação
    paralela?
    ●   Melhor aproveitamento dos recursos de hardware;
    ●   Aumento do desempenho das aplicações (nem
        sempre).
Processos e threads
●   Processos: são programas em execução que
    ocupam uma região própria na memória e
    podem ser distribuídos para processadores
    pelo sistema operacional;
●   Threads: são fluxos de execução de um
    mesmo processo que compartilham a região de
    memória do processo.
Processos e threads
●   Criar um novo processo a partir de um
    processo existente consiste em alocar uma
    região nova de memória contendo uma cópia
    do processo criador;
●   Criar uma thread consiste em alocar uma
    pequena região de memória contendo as
    informações da thread, o resto é compartilhado
    com o processo criador.
A libdispatch
A libdispatch
●   Biblioteca criada pela Apple para facilitar a
    utilização    de   multiprocessamento     nas
    aplicações;
●   Abstrai o processo de criação e manutenção de
    threads;
●   “Escreva menos código e faça mais”;
Blocks
●   Extensão da linguagem C criada pela Apple e usada pelo
    GCD para encapsular tarefas.

      typedef void (^UmBlocoVoid)();


      UmBlocoVoid bloco = ^{
           printf("Dentro de um Blockn");
           int i;
           for(i=0;i<100;i++){
                printf("Exemplo %dn", i);
           }
      };
Dispatch Queues
●   São filas para onde as tarefas serão enviadas
    e, uma a uma, retiradas e processadas;
●   O GCD disponibiliza 3 tipos de filas;
    ●   Main Queue (Serial);
    ●   Private Queue (Serial);
    ●   Global Queue (Concorrente);
Dispatch Queues (exemplo)
#include <dispatch/dispatch.h>
.
.
.
    dispatch_queue_t fila1;
    dispatch_queue_t fila2;
    dispatch_queue_t fila3;


    fila1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
        0);
    fila2 = dispatch_queue_create(“queue label”, 0);
    fila3 = dispatch_get_main_queue();
Executando tarefas
●   Tarefas podem ser enviadas para as filas com
    as seguintes funcões:
    ●   dispatch_sync();
    ●   dispatch_async();
    ●   dispatch_apply();
    ●   dispatch_sync_f();
    ●   dispatch_async_f();
    ●   dispatch_apply_f().
Executando tarefas (exemplo)
dispatch_sync(queue, ^{
      // Tarefa para ser processada de maneira síncrona
});


dispatch_async(queue, ^{
      // Tarefa para ser processada de maneira assíncrona
});
Paralelizando loops
●   Iterações de um loop podem ser paralelizadas
    com a função dispatch_apply():

      dispatch_apply(ITERACOES, queue, ^(size_t i){
            // loop
      });
Grupos
●   Permitem bloquear a execução do programa
    para esperar que uma ou mais      threads
    terminem (join);

    dispatch_group_t grupo = dispatch_group_create();
    dispatch_queue_t fila = dispatch_get_global_queue(0, 0);
    dispatch_group_async(grupo, fila, ^{
          // bloco de execução
    });
    dispatch_group_wait(grupo, DISPATCH_TIME_FOREVER);
Semáforos
●   Mecanismo de sincronização que possibilita a
    exclusão mútua e o controle do uso de recursos
    limitados;

    dispatch_semaphore_t sema = dispatch_semaphore_create(1);
    …
    dispatch_async(fila, ^{
          …
          dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
          // Região crítica
          dispatch_semaphore_signal(sema);
    });
Dispatch Sources
●   Mecanismo criado para detectar e processar
    eventos do sistema;
●   Um dispatch source pode substituir os recursos
    nativos de tratamento assíncrono de eventos (poll,
    epoll, kqueue e etc);
●   Um dispatch source permite:
    ●   Criar timers;
    ●   Monitorar sinais enviados pelo sistema;
    ●   Monitorar descritores de arquivos;
    ●   Monitorar processos (exit, fork, exec e etc).
Dispatch Sources (exemplo)
●   Criando um timer:
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_source_t timer = dispatch_source_create(
       DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(timer, 0ull, 1ull * NSEC_PER_SEC,
       1ull * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{ printf("Eventon"); });
    dispatch_resume(timer);
Dispatch Sources (exemplo)
●   Criando um leitor de arquivo:
    int f = open("/etc/services", O_RDONLY|O_NONBLOCK);
    dispatch_source_t source =
    dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, f, 0, queue);
    dispatch_source_set_event_handler(source, ^{
          size_t resto = dispatch_source_get_data(source);
          printf("Dados restantes %lun", resto);
          read(f, dados, 1024);
    });
    dispatch_source_set_cancel_handler(source, ^{
          close(f);
    });
    dispatch_resume(source);
Perguntas?
Referências
●   Mac OS forge - http://libdispatch.macosforge.org/
●   Apache GCD MPM - http://libdispatch.macosforge.org/trac/wiki/apache
●   GCD no FreeBSD - http://wiki.freebsd.org/GCD
●   Concurrency Programming Guide -
    http://developer.apple.com/library/mac/#documentation/General/Conceptual/
    ConcurrencyProgrammingGuide/Introduction/Introduction.html
●   Grand Central Dispatch (GCD) Reference -
    http://developer.apple.com/library/mac/#documentation/Performance/Refere
    nce/GCD_libdispatch_Ref/Reference/reference.html
●   Blocks Programming Topics
    http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Bl
    ocks/Articles/00_Introduction.html#//apple_ref/doc/uid/TP40007502

Mais conteúdo relacionado

Mais procurados

Cap1 exercicios comandos linux resolucao part i
Cap1 exercicios comandos linux   resolucao part iCap1 exercicios comandos linux   resolucao part i
Cap1 exercicios comandos linux resolucao part iportal_Do_estudante
 
Python e Linux para a criação de ferramentas para pentest
Python e Linux para a criação de ferramentas para pentestPython e Linux para a criação de ferramentas para pentest
Python e Linux para a criação de ferramentas para pentestEdson Celio
 
Sistemas operacionais1
Sistemas operacionais1Sistemas operacionais1
Sistemas operacionais1Nauber Gois
 
Aula Simulação por Eventos Discretos
Aula Simulação por Eventos DiscretosAula Simulação por Eventos Discretos
Aula Simulação por Eventos DiscretosAntonio Marcos Alberti
 
Aplicando o poder de uma GPU no SQL Server
Aplicando o poder de uma GPU noSQL ServerAplicando o poder de uma GPU noSQL Server
Aplicando o poder de uma GPU no SQL Serverpichiliani
 
Threads 07: Sincronizadores
Threads 07: SincronizadoresThreads 07: Sincronizadores
Threads 07: SincronizadoresHelder da Rocha
 
Linguagens de Script: Caso de Estudo Lua
Linguagens de Script: Caso de Estudo LuaLinguagens de Script: Caso de Estudo Lua
Linguagens de Script: Caso de Estudo LuaSérgio Souza Costa
 
Atualização Java 8 (2014)
Atualização Java 8 (2014)Atualização Java 8 (2014)
Atualização Java 8 (2014)Helder da Rocha
 
Tutorial dev cpp 002 - criação, leitura e alteração de arquivos
Tutorial dev cpp   002 - criação, leitura e alteração de arquivosTutorial dev cpp   002 - criação, leitura e alteração de arquivos
Tutorial dev cpp 002 - criação, leitura e alteração de arquivosFlávio Freitas
 
Introdução à biblioteca OpenCV
Introdução à biblioteca OpenCVIntrodução à biblioteca OpenCV
Introdução à biblioteca OpenCVGuto Kaberdock
 
Threads 10: CompletableFuture
Threads 10: CompletableFutureThreads 10: CompletableFuture
Threads 10: CompletableFutureHelder da Rocha
 
Comparação Sintaxe Portugol vs Java
Comparação Sintaxe Portugol vs JavaComparação Sintaxe Portugol vs Java
Comparação Sintaxe Portugol vs JavaMario Sergio
 

Mais procurados (20)

Cap1 exercicios comandos linux resolucao part i
Cap1 exercicios comandos linux   resolucao part iCap1 exercicios comandos linux   resolucao part i
Cap1 exercicios comandos linux resolucao part i
 
Threads 09: Paralelismo
Threads 09: ParalelismoThreads 09: Paralelismo
Threads 09: Paralelismo
 
Programação funcional no dia a dia
Programação funcional no dia a diaProgramação funcional no dia a dia
Programação funcional no dia a dia
 
Python e Linux para a criação de ferramentas para pentest
Python e Linux para a criação de ferramentas para pentestPython e Linux para a criação de ferramentas para pentest
Python e Linux para a criação de ferramentas para pentest
 
Sistemas operacionais1
Sistemas operacionais1Sistemas operacionais1
Sistemas operacionais1
 
Aula Simulação por Eventos Discretos
Aula Simulação por Eventos DiscretosAula Simulação por Eventos Discretos
Aula Simulação por Eventos Discretos
 
Aplicando o poder de uma GPU no SQL Server
Aplicando o poder de uma GPU noSQL ServerAplicando o poder de uma GPU noSQL Server
Aplicando o poder de uma GPU no SQL Server
 
Threads 07: Sincronizadores
Threads 07: SincronizadoresThreads 07: Sincronizadores
Threads 07: Sincronizadores
 
Linguagens de Script: Caso de Estudo Lua
Linguagens de Script: Caso de Estudo LuaLinguagens de Script: Caso de Estudo Lua
Linguagens de Script: Caso de Estudo Lua
 
Pilha em C
Pilha em CPilha em C
Pilha em C
 
Atualização Java 8 (2014)
Atualização Java 8 (2014)Atualização Java 8 (2014)
Atualização Java 8 (2014)
 
Tutorial dev cpp 002 - criação, leitura e alteração de arquivos
Tutorial dev cpp   002 - criação, leitura e alteração de arquivosTutorial dev cpp   002 - criação, leitura e alteração de arquivos
Tutorial dev cpp 002 - criação, leitura e alteração de arquivos
 
Introdução à biblioteca OpenCV
Introdução à biblioteca OpenCVIntrodução à biblioteca OpenCV
Introdução à biblioteca OpenCV
 
ESTRUTURA DE DADOS (JAVA) AULA 09
ESTRUTURA DE DADOS (JAVA) AULA 09ESTRUTURA DE DADOS (JAVA) AULA 09
ESTRUTURA DE DADOS (JAVA) AULA 09
 
Threads 10: CompletableFuture
Threads 10: CompletableFutureThreads 10: CompletableFuture
Threads 10: CompletableFuture
 
OpenSolaris a Céu Aberto
OpenSolaris a Céu AbertoOpenSolaris a Céu Aberto
OpenSolaris a Céu Aberto
 
Introdução ao Processamento Paralelo (2)
Introdução ao Processamento Paralelo (2)Introdução ao Processamento Paralelo (2)
Introdução ao Processamento Paralelo (2)
 
Palestra2009
Palestra2009Palestra2009
Palestra2009
 
Apresentação Lua
Apresentação LuaApresentação Lua
Apresentação Lua
 
Comparação Sintaxe Portugol vs Java
Comparação Sintaxe Portugol vs JavaComparação Sintaxe Portugol vs Java
Comparação Sintaxe Portugol vs Java
 

Destaque

Introdução ao LaTeX
Introdução ao LaTeXIntrodução ao LaTeX
Introdução ao LaTeXflisolmaringa
 
Platinum Arts Sandbox - Game Maker
Platinum Arts Sandbox - Game MakerPlatinum Arts Sandbox - Game Maker
Platinum Arts Sandbox - Game Makerflisolmaringa
 
Desenvolvimento de jogos para iOS com Cocos2d
Desenvolvimento de jogos para iOS com Cocos2dDesenvolvimento de jogos para iOS com Cocos2d
Desenvolvimento de jogos para iOS com Cocos2dflisolmaringa
 
Apresentando o FreeBSD
Apresentando o FreeBSDApresentando o FreeBSD
Apresentando o FreeBSDflisolmaringa
 
ZFS – Zettabyte File System
ZFS – Zettabyte File SystemZFS – Zettabyte File System
ZFS – Zettabyte File Systemflisolmaringa
 
Apresentando o FreeBSD
Apresentando o FreeBSDApresentando o FreeBSD
Apresentando o FreeBSDflisolmaringa
 

Destaque (9)

Introdução ao LaTeX
Introdução ao LaTeXIntrodução ao LaTeX
Introdução ao LaTeX
 
Platinum Arts Sandbox - Game Maker
Platinum Arts Sandbox - Game MakerPlatinum Arts Sandbox - Game Maker
Platinum Arts Sandbox - Game Maker
 
Desenvolvimento de jogos para iOS com Cocos2d
Desenvolvimento de jogos para iOS com Cocos2dDesenvolvimento de jogos para iOS com Cocos2d
Desenvolvimento de jogos para iOS com Cocos2d
 
Linux de A a Z
Linux de A a ZLinux de A a Z
Linux de A a Z
 
Linguagem Go
Linguagem GoLinguagem Go
Linguagem Go
 
Apresentando o FreeBSD
Apresentando o FreeBSDApresentando o FreeBSD
Apresentando o FreeBSD
 
ZFS – Zettabyte File System
ZFS – Zettabyte File SystemZFS – Zettabyte File System
ZFS – Zettabyte File System
 
FreeBSD
FreeBSDFreeBSD
FreeBSD
 
Apresentando o FreeBSD
Apresentando o FreeBSDApresentando o FreeBSD
Apresentando o FreeBSD
 

Semelhante a Introdução ao processamento paralelo com o Grand Central Dispatch

Mini-curso Programação Paralela e Distribuída
Mini-curso Programação Paralela e DistribuídaMini-curso Programação Paralela e Distribuída
Mini-curso Programação Paralela e DistribuídaDeivid Martins
 
Sistemas Operativos - Processos e Threads
Sistemas Operativos - Processos e ThreadsSistemas Operativos - Processos e Threads
Sistemas Operativos - Processos e ThreadsPedro De Almeida
 
Lógica de programação pascal
Lógica de programação   pascalLógica de programação   pascal
Lógica de programação pascalJocelma Rios
 
Máquinas Multiníveis - Nível da Microarquitetura
Máquinas Multiníveis - Nível da MicroarquiteturaMáquinas Multiníveis - Nível da Microarquitetura
Máquinas Multiníveis - Nível da MicroarquiteturaLincoln Lamas
 
Linux4all#2
Linux4all#2Linux4all#2
Linux4all#2Daniel
 
Exemplos de uso de apache spark usando aws elastic map reduce
Exemplos de uso de apache spark usando aws elastic map reduceExemplos de uso de apache spark usando aws elastic map reduce
Exemplos de uso de apache spark usando aws elastic map reduceFelipe
 
Escrevendo modulos python com rust
Escrevendo modulos python com rustEscrevendo modulos python com rust
Escrevendo modulos python com rustBruno Rocha
 
Phpjedi 090307090434-phpapp01 2
Phpjedi 090307090434-phpapp01 2Phpjedi 090307090434-phpapp01 2
Phpjedi 090307090434-phpapp01 2PrinceGuru MS
 
A arquitetura básica de um computador
A arquitetura básica de um computadorA arquitetura básica de um computador
A arquitetura básica de um computadorredesinforma
 
Aplicações com Tecnologias Web
Aplicações com Tecnologias WebAplicações com Tecnologias Web
Aplicações com Tecnologias WebRildo Pragana
 
Coroutine e concorrência python
Coroutine e concorrência   python Coroutine e concorrência   python
Coroutine e concorrência python Kaueh Moreno
 
Prog shell
Prog shellProg shell
Prog shellTiago
 
Principais conceitos técnicas e modelos de programação paralela
Principais conceitos técnicas e modelos de programação paralelaPrincipais conceitos técnicas e modelos de programação paralela
Principais conceitos técnicas e modelos de programação paralelaIntel Software Brasil
 

Semelhante a Introdução ao processamento paralelo com o Grand Central Dispatch (20)

Mini-curso Programação Paralela e Distribuída
Mini-curso Programação Paralela e DistribuídaMini-curso Programação Paralela e Distribuída
Mini-curso Programação Paralela e Distribuída
 
Sistemas Operativos - Processos e Threads
Sistemas Operativos - Processos e ThreadsSistemas Operativos - Processos e Threads
Sistemas Operativos - Processos e Threads
 
Curso openmp
Curso openmpCurso openmp
Curso openmp
 
Lógica de programação pascal
Lógica de programação   pascalLógica de programação   pascal
Lógica de programação pascal
 
Palestra cbq
Palestra cbqPalestra cbq
Palestra cbq
 
Máquinas Multiníveis - Nível da Microarquitetura
Máquinas Multiníveis - Nível da MicroarquiteturaMáquinas Multiníveis - Nível da Microarquitetura
Máquinas Multiníveis - Nível da Microarquitetura
 
Linux4all#2
Linux4all#2Linux4all#2
Linux4all#2
 
Exemplos de uso de apache spark usando aws elastic map reduce
Exemplos de uso de apache spark usando aws elastic map reduceExemplos de uso de apache spark usando aws elastic map reduce
Exemplos de uso de apache spark usando aws elastic map reduce
 
Kernel cooperativo
Kernel cooperativoKernel cooperativo
Kernel cooperativo
 
Utilizando Docker para escalonar aplicações Node.Js
Utilizando Docker para escalonar aplicações Node.JsUtilizando Docker para escalonar aplicações Node.Js
Utilizando Docker para escalonar aplicações Node.Js
 
Escrevendo modulos python com rust
Escrevendo modulos python com rustEscrevendo modulos python com rust
Escrevendo modulos python com rust
 
Phpjedi 090307090434-phpapp01 2
Phpjedi 090307090434-phpapp01 2Phpjedi 090307090434-phpapp01 2
Phpjedi 090307090434-phpapp01 2
 
M2ti - Python Brasil
M2ti - Python BrasilM2ti - Python Brasil
M2ti - Python Brasil
 
A arquitetura básica de um computador
A arquitetura básica de um computadorA arquitetura básica de um computador
A arquitetura básica de um computador
 
Aplicações com Tecnologias Web
Aplicações com Tecnologias WebAplicações com Tecnologias Web
Aplicações com Tecnologias Web
 
Modern PHP
Modern PHPModern PHP
Modern PHP
 
Coroutine e concorrência python
Coroutine e concorrência   python Coroutine e concorrência   python
Coroutine e concorrência python
 
Prog shell
Prog shellProg shell
Prog shell
 
Ud2
Ud2Ud2
Ud2
 
Principais conceitos técnicas e modelos de programação paralela
Principais conceitos técnicas e modelos de programação paralelaPrincipais conceitos técnicas e modelos de programação paralela
Principais conceitos técnicas e modelos de programação paralela
 

Introdução ao processamento paralelo com o Grand Central Dispatch

  • 1. Introdução ao Grand Central Dispatch
  • 2. Programação paralela ● O que é programação paralela? ● Por que se preocupar com programação paralela? ● Melhor aproveitamento dos recursos de hardware; ● Aumento do desempenho das aplicações (nem sempre).
  • 3. Processos e threads ● Processos: são programas em execução que ocupam uma região própria na memória e podem ser distribuídos para processadores pelo sistema operacional; ● Threads: são fluxos de execução de um mesmo processo que compartilham a região de memória do processo.
  • 4. Processos e threads ● Criar um novo processo a partir de um processo existente consiste em alocar uma região nova de memória contendo uma cópia do processo criador; ● Criar uma thread consiste em alocar uma pequena região de memória contendo as informações da thread, o resto é compartilhado com o processo criador.
  • 6. A libdispatch ● Biblioteca criada pela Apple para facilitar a utilização de multiprocessamento nas aplicações; ● Abstrai o processo de criação e manutenção de threads; ● “Escreva menos código e faça mais”;
  • 7. Blocks ● Extensão da linguagem C criada pela Apple e usada pelo GCD para encapsular tarefas. typedef void (^UmBlocoVoid)(); UmBlocoVoid bloco = ^{ printf("Dentro de um Blockn"); int i; for(i=0;i<100;i++){ printf("Exemplo %dn", i); } };
  • 8. Dispatch Queues ● São filas para onde as tarefas serão enviadas e, uma a uma, retiradas e processadas; ● O GCD disponibiliza 3 tipos de filas; ● Main Queue (Serial); ● Private Queue (Serial); ● Global Queue (Concorrente);
  • 9. Dispatch Queues (exemplo) #include <dispatch/dispatch.h> . . . dispatch_queue_t fila1; dispatch_queue_t fila2; dispatch_queue_t fila3; fila1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); fila2 = dispatch_queue_create(“queue label”, 0); fila3 = dispatch_get_main_queue();
  • 10. Executando tarefas ● Tarefas podem ser enviadas para as filas com as seguintes funcões: ● dispatch_sync(); ● dispatch_async(); ● dispatch_apply(); ● dispatch_sync_f(); ● dispatch_async_f(); ● dispatch_apply_f().
  • 11. Executando tarefas (exemplo) dispatch_sync(queue, ^{ // Tarefa para ser processada de maneira síncrona }); dispatch_async(queue, ^{ // Tarefa para ser processada de maneira assíncrona });
  • 12. Paralelizando loops ● Iterações de um loop podem ser paralelizadas com a função dispatch_apply(): dispatch_apply(ITERACOES, queue, ^(size_t i){ // loop });
  • 13. Grupos ● Permitem bloquear a execução do programa para esperar que uma ou mais threads terminem (join); dispatch_group_t grupo = dispatch_group_create(); dispatch_queue_t fila = dispatch_get_global_queue(0, 0); dispatch_group_async(grupo, fila, ^{ // bloco de execução }); dispatch_group_wait(grupo, DISPATCH_TIME_FOREVER);
  • 14. Semáforos ● Mecanismo de sincronização que possibilita a exclusão mútua e o controle do uso de recursos limitados; dispatch_semaphore_t sema = dispatch_semaphore_create(1); … dispatch_async(fila, ^{ … dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); // Região crítica dispatch_semaphore_signal(sema); });
  • 15. Dispatch Sources ● Mecanismo criado para detectar e processar eventos do sistema; ● Um dispatch source pode substituir os recursos nativos de tratamento assíncrono de eventos (poll, epoll, kqueue e etc); ● Um dispatch source permite: ● Criar timers; ● Monitorar sinais enviados pelo sistema; ● Monitorar descritores de arquivos; ● Monitorar processos (exit, fork, exec e etc).
  • 16. Dispatch Sources (exemplo) ● Criando um timer: dispatch_queue_t queue = dispatch_get_global_queue(0, 0); dispatch_source_t timer = dispatch_source_create( DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); dispatch_source_set_timer(timer, 0ull, 1ull * NSEC_PER_SEC, 1ull * NSEC_PER_SEC); dispatch_source_set_event_handler(timer, ^{ printf("Eventon"); }); dispatch_resume(timer);
  • 17. Dispatch Sources (exemplo) ● Criando um leitor de arquivo: int f = open("/etc/services", O_RDONLY|O_NONBLOCK); dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, f, 0, queue); dispatch_source_set_event_handler(source, ^{ size_t resto = dispatch_source_get_data(source); printf("Dados restantes %lun", resto); read(f, dados, 1024); }); dispatch_source_set_cancel_handler(source, ^{ close(f); }); dispatch_resume(source);
  • 19. Referências ● Mac OS forge - http://libdispatch.macosforge.org/ ● Apache GCD MPM - http://libdispatch.macosforge.org/trac/wiki/apache ● GCD no FreeBSD - http://wiki.freebsd.org/GCD ● Concurrency Programming Guide - http://developer.apple.com/library/mac/#documentation/General/Conceptual/ ConcurrencyProgrammingGuide/Introduction/Introduction.html ● Grand Central Dispatch (GCD) Reference - http://developer.apple.com/library/mac/#documentation/Performance/Refere nce/GCD_libdispatch_Ref/Reference/reference.html ● Blocks Programming Topics http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Bl ocks/Articles/00_Introduction.html#//apple_ref/doc/uid/TP40007502