Grand Central Dispatch

**Grand Central Dispatch** (**GCD**), Apple-дың көпядролы процессорлар және басқа да SMP-жүйелердің артықшылықтарын  пайдаланатын қосымшаларды құру үшін арналған технологиясы, Нью-Йорктегі Grand Central Terminal орталық вокзал атауын тұспалдайды. Бұл технология міндеттердің параллелизмін іске асырылуына және "Ағымдар пулы" жобалау үлгісіне негізделген. GCD алғаш рет Mac OS X 10.6-да ұсынылды. GCD сервистерін іске асыратын  **libdispatch **кітапханасының бастапқы кодтары Apache лицензиясы астында 10 қыркүйекте 2009 жhttp://libdispatch.macosforge.org/. шығарылды. Кейіннен кітапхана басқа FreeBSD операциялық жүйесіне портталды.

GCD қосымшада міндеттердің параллель орындалуы мүмкіндерін анықтауға мүмкіндік береді, және оларды бос есептеуіш ресурстар (процессорлық ядролар) болғанда іске қосады.

Міндет функция немесе "блок" ретінде айқындалуы мүмкін. Блок — бұл стандартты емес C/C++/Objective-C бағдарламалау тілдерінің синтаксисінің кеңейтілуі, бұл кодтарды және деректерді бір объектіге инкапсуляциялауға мүмкіндік береді, тұйықталу аналогы.

Grand Central Dispatch ағындарды төмен деңгейде пайдаланады, бірақ іске асыру  бөлшектерін бағдарламашыдан жасырады. GCD міндеттері жеңіл, құру және ауыстыру қымбат емес; Apple-дың сендіруінше, тапсырмаларды кезекке қосу 15 процессорлық нұсқаулықтарды ғана талап етеді, ал дәстүрлі ағынды құруға бірнеше жүздеген нұсқаулықтар қажет.

GCD міндеті жұмыс элементін құру үшін пайдаланылуы мүмкін, ол міндеттер кезегіне орналастырылады, не оқиғалар көзіне байланыстырылуы мүмкін. Екінші жағдайда іске қосылған кезде  міндет оқиғалары тиісті кезекке қосылады. Apple айтуынша, бұл нұсқа, оқиғалардың іске қосылуы күтуге жеке ағын құрғанға қарағанда, неғұрлым тиімді.

## Платформа ерекшеліктері
GCD платформасы бірнеше типтегі деректер құру және оларды басқару үшін функцияларын жариялайды.
* **Dispatch Queues** — бұл кезектегі міндеттерді қолдайтын (анонимді блок, немесе функциялар), және бұл міндеттер кезек тәртібімен іске қосатын объектілер. Кітапхана автоматты түрде әр түрлі деңгейдегі басымдықпен орындайтын бірнеше кезектер құрады және бір мезгілде бірнеше тапсырмаларды іске қосу үшін автоматты түрде міндеттердің оңтайлы санын таңдайды. Кітапхананы қолданушы дәйекті кезектің  кез келген санын жасауы мүмкін, олар бір жолы міндеттердің қосылу тәртібімен іске қосады. Өйткені дәйекті кезек әр уақытта тек бір ғана міндет орындай алады, осындай кезектерді бөлінетін ресурстарын синхрондауға қол жеткізуге болады .
* **Dispatch Sources** — бұл блоктарды тіркеуге мүмкіндік беретін объектілер немесе оларды белгілі бір оқиғаның іске қосылған кезінде асинхронды орындалуы үшін функциялар.
* **Dispatch Groups** — бұл объектілер біріктіруге мүмкіндік беретін міндеттер тобын кейіннен бірлестіктер (joining). Міндеттері қосылған болуы мүмкін да топ мүшелері, содан кейін объект топ үшін пайдаланылуы мүмкін күту аяқталғаннан барлық міндеттер.
* **Dispatch Semaphores** — бұл міндеттердің белгілі бір санынан аспайтын бір мезгілде орындалуына мүмкіндік беретін объектілер. Қрз. семафор.

## Мысалдар
Екі мысал Grand Central Dispatch пайдалану қарапайымдылығын көрсететін Джон Сиракузаның Ars Technica-дағы Snow Leopard  шолуында табылуы мүмкін..

### Асинхронды шақыру
Бастапқыда, бізде  құжаттағы сөздер мен параграфтардың санауды жүзеге асыратын analyzeDocument әдісімен қосымша бар. Әдетте, сөздер мен параграфтарды санау процессі жеткілікті түрде тез және басты ағында орындалуы мүмкін, бұл дегеніңіз, қолданушы түймені басқан және нәтижесін алған арасындағы орын алған кідірісті байқайды:


```objc
- (IBAction)analyzeDocument:(NSButton *)sender {
    NSDictionary *stats = [myDoc analyse];
    [myModel setDict:stats];
    [myStatsView setNeedsDisplay:YES];
  }
```


Егер құжат өте үлкен болса, талдау үшін айтарлықтай көп уақыт кетуі мүмкін. онда қолданушы "іркілуді" байқайды. Келесі мысал бұл мәселені оңай шешеді:


```objc
- (IBAction)analyzeDocument:(NSButton *)sender 
{

     dispatch_async(dispatch_get_global_queue(0, 0), ^{
         NSDictionary *stats = [myDoc analyze];
         dispatch_async(dispatch_get_main_queue(), ^{
           [myModel setDict:stats];
           [myStatsView setNeedsDisplay:YES];
         });
     });
}
```


Мұнда [myDoc analyze] шақыру блокқа орналастырылуы мүмкін, содан кейін жаһандық кезектердің  біріне орналастырылады. [myDoc analyze] жұмысын аяқтағаннан кейін, жаңа блок басты кезекке орналастырылады, ол пайдаланушы интерфейсін жаңартады. Осы күрделі емес өзгерістерді өткізе отырып, бағдарламашы үлкен құжаттарды талдау кезінде әлеуетті "" құтылады.

### Цикл паралельденуі
Екінші мысал циклдың паралельденуін көрсетеді:


```c
for (i = 0; i < count; i++) {
      results[i] = do_work(data, i);
}
total = summarize(results, count);
```


Мұнда do_work функциясы *count* рет шақырылады, оның нәтижесі i-ші орындалуы results массивінің i-ші элементіне беріледі, содан кейін нәтижелері қосылады. do_works алдыңғы шақыруларының нәтижелеріне арқа сүйейді деп пайымдауға негіз жоқ, сондықтан бірнеше қоңырауларды do_works параллель шақыруға еш кедергі жоқ. Келесі листинг, осы идеяның GCD көмегімен  іске асырылуын көрсетеді:


```c
dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t i){
     results[i] = do_work(data, i);
    });
total = summarize(results, count);
```


Бұл мысалда dispatch_apply *count* рет блокты іске қосады, оған әрбір қоңырауды жаһандық кезекке бере отырып, блоктарға 0-ден count-1 санын береді. Бұл ОЖ-ге неғұрлым  қол жетімді аппараттық ресурстарды толық пайдалану үшін ағындардың оңтайлы санын таңдауға  мүмкіндік береді. dispatch_apply, оның барлық блоктары жұмыстарын аяқтамайынша, басқаруды қайтармайды, бұл summarize шақырылуы алдында бастапқы циклдың барлық жұмысы орындалғанына кепілдік беруге мүмкіндік береді.

### Құру тізбекті кезек
Әзірлеуші  бірінен соң бірі орындалуы тиіс дәйекті міндеттер үшін жеке дәйекті кезек құра алады, бірақ жеке ағында жұмыс істей алады. Жаңа кезек осылайша  құрылуы мүмкін:


```c
dispatch_queue_t exampleQueue;
exampleQueue = dispatch_queue_create( "com.example.unique.identifier", NULL );

// exampleQueue осы жерде пайдалануы мүмкін.

dispatch_release( exampleQueue );
```


Мұндай міндеттерді, басқа міндетті дәл сол кезекке салатын дәйекті кезекке орналастырудан аулақ болыңыз. Бұл міндетті түрде тұйыққа (deadlock) әкеледі. Келесі листингіде осындай жағдайдағы тұйық көрсетілген:

## Сондай-ақ, қараңыз
* Блоктар (Си тілі үшін кеңейтілім)
* OpenMP — C, C++, Fortran үшін ашық стандарт.
* Intel TBB — Intel-ден ашық бастамалармен C++кітапхана.
* Task Parallel Library — Microsoft әзірлеген .NET-технологиясы.
* Java Concurrency — Java-технология (сондай-ақ JSR 166 ретінде белгілі).

## Сілтемелер