美文网首页
iOS开发之多线程的四种实现方式

iOS开发之多线程的四种实现方式

作者: 夜之海澜 | 来源:发表于2019-06-27 14:18 被阅读0次

    多线程的优缺点:
    优点:
    1,简化了编程模型
    2,更加的轻量级
    3,提高了执行效率
    4,提高了资源利用率

    缺点:
    1,增加了程序设计复杂性
    2,占用内存空间
    3,增大了CPU的调度开销

    多线程的实现方法:

    • pThread
    • NSThread
    • GCD
    • NSOperation

    PThread: 是基于C框架的,在iOS中不常用;
    创建方法及基础用法如下:

    #pragma mark - PThread
    - (void)clickPThread {
        NSLog(@"我在主线程中执行");
        //参数一:pthread指针 参数二:没什么用  设置成null 参数三:任务执行的方法  参数四:没什么用  设置成null
        pthread_t pthread;
        pthread_create(&pthread, NULL, run, NULL);
        
    }
    
    //C语言写法
    void *run(void *data) {
        NSLog(@"我在子线程中执行");
        for (int i = 1; i < 10; i++) {
            NSLog(@"%d",i);
            sleep(1);
        }
        return NULL;
    }
    
    在控制台打印出来的信息可见: 1561449723563.jpg

    其中打印日志中threadTest[26985:4948615] ,26985是进程的ID,而进程ID的后面4948615则是当前进程中的一个线程的线程ID,由此可知是在不同的线程中执行的。

    NSThread: 苹果封装后的,并且是完全面向对象的,便于操作对象
    有两种创建方式:

    • 第一种 alloc init方式
    #pragma mark - NSThread
    - (void)clickNSThread {
        NSLog(@"我在主线程中执行");
        NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(runThread1) object:nil];
        [thread1 start];
    }
    
    - (void)runThread1 {
        NSLog(@"我在子线程中执行");
        for (int i = 1; i < 10; i++) {
            NSLog(@"%d",i);
            sleep(1);
        }
    }
    
    • 第二种 detachNewThreadSelector 方式
        [NSThread detachNewThreadSelector:@selector(runThread1) toTarget:self withObject:nil];
    
    • 第三种 performSelectorInBackground 方式
        [self performSelectorInBackground:@selector(runThread1) withObject:nil];
    

    以上三种NSThread的创建方法中,二和三是没有创建相应的对象,无法操作其对象的属性,比如给NSThread的属性设置线程名字,可以更好的进行问题的定位。还可以设置优先级,如下图中,则thread2先执行,thread1后执行

    - (void)clickNSThread {
        NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(runThread1) object:nil];
        [thread1 setName:@"Name_Thread1"];
        [thread1 setThreadPriority:0.5];
        [thread1 start];
        
        NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(runThread1) object:nil];
        [thread2 setName:@"Name_Thread2"];
        [thread2 setThreadPriority:0.5];
        [thread2 start];
    }
    
    - (void)runThread1 {
       NSLog(@"%@",[NSThread currentThread].name);//输出 Name_Thread1  Name_Thread2
        for (int i = 1; i < 10; i++) {
            NSLog(@"%d",i);
            sleep(1);
        }
    }
    

    GCD
    任务分同步和异步,同步会阻塞线程,异步不会,dispatch_sync 线程同步、dispatch_async线程异步;
    队列分串行和并行;
    dispatch_get_global_queue是全局并行队列;
    下面看简单的例子:
    第一个:同步线程并行队列

        //线程同步,并行队列
        //因为是同步线程,执行起来则是顺序执行的
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"执行 task 1");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"end task 1 ");
        });
        
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"执行 task 2");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"end task 2 ");
        });
        
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"执行 task 3");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"end task 3 ");
        });
    

    这个例子中,无论执行多少次,打印顺序都是固定的,即


    同步线程的并行执行的顺序

    再来看第二个例子:异步线程并行队列

        //线程异步,并行队列,打印结果不可预期
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"执行 task 1");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"end task 1 ");
        });
    
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"执行 task 2");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"end task 2 ");
        });
    
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"执行 task 3");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"end task 3 ");
        });
    

    这个例子中,多次执行会发现,顺序并不是一成不变的,可能每次都不一样,无规律可循,即并行执行的特点。打印日志如下(此处我打印了三次)


    线程异步的并行队列的执行顺序

    再来看第三个例子:异步线程串行队列

    //第二个参数传NULL,则创建出的是串行队列
    //串行队列对应一个线程
    dispatch_queue_t queue = dispatch_queue_create("com.gcd.test", NULL);
        dispatch_async(queue, ^{
            NSLog(@"执行 task 1");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"end task 1 ");
    
        });
        
        dispatch_async(queue, ^{
            NSLog(@"执行 task 2");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"end task 2 ");
            
        });
        
        dispatch_async(queue, ^{
            NSLog(@"执行 task 3");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"end task 3 ");
            
        });
    

    打印结果如下:


    image.png

    如上图可发现,是在同一进程同一线程中顺序执行的,即串行队列对应一个线程。

    第四个例子:异步线程并行队列

     //手动创建的并行队列
        dispatch_queue_t queue = dispatch_queue_create("com.gcd.test", DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(queue, ^{
            NSLog(@"执行 task 1");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"end task 1 ");
            
        });
        
        dispatch_async(queue, ^{
            NSLog(@"执行 task 2");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"end task 2 ");
            
        });
        
        dispatch_async(queue, ^{
            NSLog(@"执行 task 3");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"end task 3 ");
            
        });
    

    打印结果如下:


    线程异步的并行队列的执行顺序

    每次打印结果都会不同,且可以看出是在同一进程的不同线程中执行,即并行队列对应不同线程。

    在iOS中是无法使用 dispatch_sync(dispatch_get_main_queue()
    dispath向主队列加一个同步的block;
    此时主队列在等待 dispatch_sync(dispatch_get_main_queue(),^(){block体});执行
    dispatch_sync在等待主队列执行完毕。
    所以在此过程中,我们最初调用的dispatch_sync函数一直得不到返回,main queue被阻塞,而我们的block又需要等待main queue来执行它。造成死锁。

    NSOperation
    NSOperation本身是一个基类,所以要使用其子类进行才能执行任务和线程。
    两种使用方式:
    1.系统封装好的NSInvocationOperation & NSBlockOperation;
    这两个子类通过直接对象调start的方式是串行执行的,
    若将其对象通过方法添加到队列中,则可以实现并行执行;
    2.自定义类继承NSOperation

    相关文章

      网友评论

          本文标题:iOS开发之多线程的四种实现方式

          本文链接:https://www.haomeiwen.com/subject/zjztcctx.html