通过Grand Central Dispatch优化程序
通过Grand Central Dispatch 优化程序
多线程编程被认为是黑色的艺术,即使是有经验的程序员,编写和维护多线程程序也是很困难和不快乐的。 所有也就尽可能的避免编写多线程程序。
多线程的目标是比较简单的:同一时间,竟可能的执行多个任务,比如在IOS用户操作时候,主线程负责绘制屏幕。 如果我们在主线程里面执行我们逻辑代码,界面线程可能不能及时的响应用户的输入。
所以呢,我们会把IO操作,复杂的计算,以及同步的网络请求。放到另外的线程中。有时候,使用多线程是没有办法的事情。
1 Grand Central Dispatch
GCD是苹果提供一种像多线程一样并行执行的技术,但是比多线程编程简单。程序员提交一个block代码到队列中,block的队列被操作系统控制和执行,以平行或者串行的形式。下面是个实例代码。
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"This is exectuted in a different thread") ;
}) ;
通过调用dispatch_async
我们来执行异步的任务。
dispatch_async(dispatch_queue_t queue, dispatch_block_t block); 有2个参数:
* `queue`,要执行任务的队列
* `block` 块
2 Dispatch Queues
我们可以使用ios提供的队列,来代替多线程操作,多线程有操作系统管理,所以这里不能够保证那个线程来执行我们的代码,
这有2种队列:
1 并行队列
任务加入的队列是先进,先出的原则,操作系统自动生成四个不同级别并行dispatch queues,既然任务是冰心的执行,所以这里没有保障任务完成的顺序。
2 串行队列
在串行的队列中,只有上一个任务完成,下一个才会入队。串行的队列保证某一时刻只有一个任务执行。串行队列确保任务执行的按照预期的顺序执行。
所以IOS系统 全局派遣队列(global dispatch queues)是并行的。
如果要使用串行队列,我们需要动过dispatch_queue_create("queue_name", 0)
产生新队列,
3 queue 优先级
- DISPATCH_QUEUE_PRIORITY_HIGH
- DISPATCH_QUEUE_PRIORITY_DEFAULT
- DISPATCH_QUEUE_PRIORITY_LOW
- DISPATCH_QUEUE_PRIORITY_BACKGROUND
上面的优先级逐次降低。
我们可以通过下面函数,来获得队列。
dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags);
4 main queue
当我们在主线程执行一些特殊的任务时候,向用户界面操作,main queue是非常有用的。比如更新label,显示信息,更新view,由于UI的操作室非线程安全的,所以我们必须在主线程中操作。 ` dispatch_async(dispatch_get_main_queue(), ^{NSLog(@”main thread”) ;}) ;`
例子
dispatch_queue_t mainQueue = dispatch_get_main_queue() ;
dispatch_async(mainQueue, ^(void){
[[ [UIAlertView alloc] initWithTitle:@"Gcd" message:@"Gcd is running" delegate:self cancelButtonTitle:@"ok" otherButtonTitles:nil, nil] show] ;
});
5 顺序执行 dispatch_sync
dispatch_sync
确保提交到队列中,上一个任务执行完成后,才会执行下一个任务
void (^printFrom1To1000)(void) = ^ {
NSUInteger counter = 0;
for(counter =1; counter <= 5000 ; counter++) {
NSLog(@"counter = %lu --thread=%@" , (unsigned long) counter ,[NSThread currentThread]) ;
}
counter =0 ;
};
dispatch_queue_t concurrentQueue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) ;
dispatch_async(concurrentQueue, ^{
dispatch_sync(concurrentQueue ,printFrom1To1000) ;
dispatch_sync(concurrentQueue ,printFrom1To1000) ;
});
6 延时调用方法 dispatch_after
-(void) printString:(NSString*) paramString {
NSLog(@"%@" , paramString) ;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//第一种方法
[self performSelector:@selector(printString:) withObject:@"Grand Central Dispatch" afterDelay:5.0 ];
double delayInSeconds = 5.0 ;
//第二种方法
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"dispatch_after") ;
});
}
7 只调用一次 dispatch_once
static dispatch_once_t onceToken ;
void (^ executOnlyOnce) (void) = ^ {
static NSUInteger numberofEntries = 0 ;
numberofEntries++ ;
NSLog(@"Exectuted %lu time(s)", (unsigned long) numberofEntries) ;
} ;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
dispatch_queue_t concurrentQueue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) ;
dispatch_once(&onceToken,^{
dispatch_async(concurrentQueue, executOnlyOnce);
}) ;
dispatch_once(&onceToken,^{
dispatch_async(concurrentQueue, executOnlyOnce);
}) ;
}
8 dispatch_group
For each resource that needs loading, run a block that does the loading into memory, and run it in the background. Then run a subsequent block when all of the blocks have completed.
You can do this through dispatch groups, which are a way to submit multiple units of work to Grand Central Dispatch:
NSArray* imagesToLoad = [NSArray array];
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
for (NSString* imageFileName in imagesToLoad) {
dispatch_group_async(group, backgroundQueue, ^{
// Load the file
}); }
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_group_notify(group, mainQueue, ^{
// All images are done loading at this point
});