GCD 编程

来源:互联网 发布:武汉软件培训 编辑:程序博客网 时间:2024/05/29 10:08
有些操作无法在异步队列运行,因此必须在主线程(每个应用都有一个)上运行。UI绘图以及任何对NSNotificationCenter的调用必须在主线程长进行。在另一个队列中访问主线程并运行代码的示例如下:

1
2
3
dispatch_sync(dispatch_get_main_queue(), ^{ 
        [self dismissLoginWindow]; }
);

实例

可以在John Siracusa的ArsTechnica博客文章Snow Leopard review中找到两个演示如何使用Grand Central Dispatch的例子。首先,一个处理文档的应用程序有一个名为analyzeDocument函数,会做一些统计文档的单词和段落的事情。通常情况下,这将是一个快速的过程,并在用户根本没注意到按下一个键和结果显示出来之间的延迟就已经在主线程中执行好了。
1
2
3
4
5
6
-(IBAction)analyzeDocument:(NSButton*)sender{
    NSDictionary*stats=[myDoc analyze];
    [myModel setDict:stats];
    [myStatsViewsetNeedsDisplay:YES];
    [stats release];
}
如果一个文档太大并且需要很长的时间去执行,那么主线程将会暂停等待这个函数完成。如果花了很长的时间,那么用户就会注意到这个延迟,应用程序甚至会没有响应。这个问题的解决方案如下:
1
2
3
4
5
6
7
8
9
-(IBAction)analyzeDocument:(NSButton*)sender{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
    NSDictionary*stats=[myDoc analyze];
    dispatch_async(dispatch_get_main_queue(),^{
        [myModel setDict:stats];
        [myStatsView setNeedsDisplay:YES];
        [stats release];});
    });
};
在这里,[myDoc analyze]的调用先被放置在了一个块中,然后进入一个全局并发队列里。在完成[myDoc analyze]的运行之后,一个新的块放置在主队列里(应用程序主线程在上面运行),更新了GUI(这是必要的,因为GUI只能由主线程更新)。通过这两个小的改动,开发人员就避免了能被用户看到的潜在的暂停并且使得应用程序更好的利用硬件资源。
第二个例子是一个并行的for循环:
1
2
3
4
for(i=0;i<count;i++){
    results[i]=do_work(data,i);
}
total=summarize(results,count);
这段代码调用的do_work函数统计次数,将第i次的结果赋值给数组的第i个元素,然后在循环结束之后调用summarize函数。这些操作时顺序执行的,实际上并不需要这样。假设do_work函数不需要其他函数调用的结果,那么这些调用就可以同时运行了。这就是在GCD中的做法:
1
2
3
4
dispatch_apply(count,dispatch_get_global_queue(0,0),^(size_ti){
    results[i]=do_work(data,i);
});
total=summarize(results,count);
这里,dispatch_apply运行传递来的块,在全局队列中放入每一次调用,并且给每次块调用一个从0到n-1的不同的数字。这样就允许操作系统通过当前的硬件和系统负载选择最佳的线程数来分配合适的工作。dispatch_apply知道所有的在给定队列的块运行完成才返回,这样就可以保证在调用summarize之前完成原来的循环里的所有事情。
程序员可以创建自己的任务队列,他们必须串行执行,但可在一个单独的线程中执行。一个新的队列可以像这样被创建:
1
2
3
4
5
dispatch_queue_t exampleQueue;
exampleQueue=dispatch_queue_create("com.example.unique.identifier",NULL);
 
//exampleQueue may be used here.
dispatch_release(exampleQueue);
必须小心,避免在队列中分配的块同步的放在同一队列的另一个块中,这是保证不会发生死锁情况。这样的代码可能会做下面的事情:
1
2
3
4
5
6
7
8
9
dispatch_queue_t exampleQueue=dispatch_queue_create("com.example.unique.identifier",NULL);
 
dispatch_sync(exampleQueue,^{
    dispatch_sync(exampleQueue,^{
        printf("I am now deadlocked...\n");
    });
});
 
dispatch_release(exampleQueue);


0 0
原创粉丝点击