IOS多线程编程之三种实现方式NSThread、NSOperation、Grand Central Dispatch

时间:2020-12-01 23:32:34

使用多线程,是软件开发中必不可少的。它的确扮演着重要的角色。

那对于多线程的实现,根据不同情况,*选择。

首先NSThread实现方式:

优点:NSThread 比其他两个轻量级

缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销


NSThread 有两种直接创建方式:

- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument

+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument

实现: 1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
2、NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:) object:nil];

3、[myThread start]; 


selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。

target  :selector消息发送的对象

argument:传输给target的唯一参数,也可以是nil

第一种方式会直接创建线程并且开始运行线程,第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息。NSThread是比较简单的多线程实现方式。通常对多线程要求不多时,可以直接写几行代码就执行了。


其次,NSOperation的实现:

使用 NSOperation的方式有两种,

一种是用定义好的两个子类:

NSInvocationOperation 和 NSBlockOperation。

另一种是继承NSOperation

如果你也熟悉Java,NSOperation就和java.lang.Runnable接口很相似。和Java的Runnable一样,NSOperation也是设计用来扩展的,只需继承重写NSOperation的一个方法main。相当与java 中Runnalbe的Run方法。然后把NSOperation子类的对象放入NSOperationQueue队列中,该队列就会启动并开始处理它。


NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self
                                                                           selector:@selector(downloadImage)
                                                                             object:nil];    
    NSInvocationOperation *operation1 = [[NSInvocationOperation alloc]initWithTarget:self
                                                                           selector:@selector(downloadImage1)
                                                                             object:nil];    
    NSInvocationOperation *operation2 = [[NSInvocationOperation alloc]initWithTarget:self
                                                                           selector:@selector(downloadImage2)
                                                                             object:nil];
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    [queue addOperation:operation];
    [queue addOperation:operation1];
    [queue addOperation:operation2];


这里做调用:

-(void)downloadImage
{
    for (int i = 0; i < 1000; i ++) {
        NSLog(@"downloadImage %d", i);
    }
    
}


-(void)downloadImage1
{
    for (int i = 0; i < 1000; i ++) {
        NSLog(@"download %d", i);
    }
    
}


-(void)downloadImage2
{
    for (int i = 0; i < 1000; i ++) {
        NSLog(@"down %d", i);
    }
    
}

从打印的日志中可以看出多线程的运作。具体线程内的实现,各自发挥。


继承NSOperation 

在.m文件中实现main方法,main方法编写要执行的代码即可。

队列里可以加入很多个NSOperation, 可以把NSOperationQueue看作一个线程池,可往线程池中添加操作(NSOperation)到队列中。线程池中的线程可看作消费者,从队列中取走操作,并执行它。

通过下面的代码设置:
[queue setMaxConcurrentOperationCount:5];
线程池中的线程数,也就是并发操作数。默认情况下是-1,-1表示没有限制,这样会同时运行队列中的全部的操作。


最后,GCD多线程实现:


dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 耗时的操作
        for (int i = 0; i < 1000; i ++) {
            NSLog(@"耗时的操作 %d", i);
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            // 更新界面
            //for (int i = 0; i < 1000; i ++) {
                //NSLog(@"更新界面 %d", i);
            //}
        });
    });


介绍:

Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统。这建立在任务并行执行的线程池模式的基础上的。它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用。

设计:

GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。

一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。

GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行
dispatch queue分为下面三种:

Serial     

又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。

Concurrent

又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。

Main dispatch queue

它是全局可用的serial queue,它是在应用程序主线程上执行任务的。

我们看看dispatch queue如何使用


2、dispatch_group_async的使用

dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。下面是一段例子代码:


dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:1];
        NSLog(@"group1");
    });
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"group2");
    });
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"group3");
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"updateUi");
    });  
    dispatch_release(group);


dispatch_barrier_async的使用:

dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行

例子代码如下:


dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_async1");
    });
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:4];
        NSLog(@"dispatch_async2");
    });
    dispatch_barrier_async(queue, ^{
        NSLog(@"dispatch_barrier_async");
        [NSThread sleepForTimeInterval:4];
        
    });
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:1];
        NSLog(@"dispatch_async3");  
    });


dispatch_apply 的使用:

执行某个代码片段N次。
dispatch_apply(5, globalQ, ^(size_t index) {
    // 执行5次
});


多线程的实现,目的在于防止卡顿、等待,充分利用现有的资源。特别是现在是多核的情况下,更要好好利用多线程。


本文属摘取他人文章,这里做归类整理,以方便自己查阅。需了解更多,请阅读原文。


著作权声明:本文由http://blog.csdn.net/totogo2010/原创,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!