服务报价 | 域名主机 | 网络营销 | 软件工具| [加入收藏]
当前位置: 主页 > 开发教程 > ios开发教程 >

iOS开发中的多线程问题

时间:2016-03-06 17:10来源:未知 作者:好模板 点击:
在分析问题之前,我们先区分两个概念:进程和线程 进程:一个正在运行的程序可以看成是一个进程。 例如正在运行的QQ,进程拥有独立运行所需要的全部资源。 线程:程序中独立运

在分析问题之前,我们先区分两个概念:进程和线程
进程:一个正在运行的程序可以看成是一个进程。 例如正在运行的QQ,进程拥有独立运行所需要的全部资源。
线程:程序中独立运行的代码段是线程。例如:接收QQ消息的代码段。
一个进程是由一个线程或者多个线程组成的,进程负责资源的调度和分配,线程才是程序真正的执行单元,负责代码的执行。
我们知道,在ios里面 会自动为UI创建一个主线程,默认主线程分配的内存空间是 1MB。我们新开辟的子线程默认是512k,分配的大小必须是4的倍数,分配给子线程的空间是用来存储变量的,所以512k是充分够用的。
iOS运行的时候 程序在主入口自动添加自动释放池 而我们自己创建的释放池是没有自动释放池的 所以要我们手动添加,添加释放吃的原因是子线程共用堆内存 如果不及时回收随着子线程数量的上升 以及大量使用便利构造器 会对系统本身造成很大的负担。

了解以上之后,我们来定义一个方法 求0-63000000的和

-(void)test{
    NSLog(@"%@,%d",[NSThread currentThread],[[NSThread mainThread]isMainThread]);
    @autoreleasepool {
        long int sum = 0;
        long int num = 63550000;
        for (long int i = 1; i <= num; i++) {
            sum +=i;
        }
        NSLog(@"%ld",sum);
 }

调用以上方法我们发现返回计算结果的时间我们还能接受 但是在63000000后面加上一个或者更多0 再次试一次 就会发现 这个时间计算机的计算速度非常慢,这时候我们就可以考虑开辟多条线程来加快程序运行效率。

二、开辟多线程有哪些方式?

1、在后台执行 开辟多线程最简单的一个方法

    [self performSelectorInBackground:@selector(test) withObject:nil];

2、NSThread
NSThread是一个轻量级的线程 创建方式有两种:

/* 第一种*/
    //1 由init来创建并且需要手动来开启
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(test) object:nil];
    //2 开启线程
    [thread start];
    //3 取消线程
    [thread cancel];//这个很少有人在用 一般也不会写在这个地方
/* 第二种 */
    //初始化的时候自动开启线程
    [NSThread detachNewThreadSelector:@selector(test) toTarget:self withObject:nil];

3、NSOperation
NSOperation是一个抽象类 他有两个子类NSInvocationOperation 和NSBlockOperation 在MVC里面属于M层 封装了单个任务的数据和相关的代码 一般我们使用它的子类

    NSInvocationOperation *incocation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test) object:nil];
    __weak typeof(self)temp = self;
    NSBlockOperation *block =[NSBlockOperation blockOperationWithBlock:^{
        [temp test];
        NSLog(@"这个是BlockOprationQueue执行的");
    }];
//NSOperationQueue是线程操作队列 用来管理一组Operation对象 会根据实际需求创建出合适数量的子线程 完成任务的并发执行
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];

    //当最大并发执行数为1的时候程序是串行执行的
    [queue setMaxConcurrentOperationCount:1];

    //设置依赖关系[A addDependency B]若A依赖B则B先执行A在执行 若B依赖A则A先执行B在执行
    [invocation addDependency:blockOperation];

    #pragma mark ---上面两部要写在添加之前---
    [queue addOperation:invocation];
    [queue addOperation:blockOperation];

我们运行一下程序结果:


由于我们做了[invocation addDependency:blockOperation];只有当blockOperation执行完成之后,invocation才能执行。结果中的number数量就是线程个数 ,0表示非主线程,1则相反。很显然 我们开辟子线程了

4、GCD
GCD 三种队列:1 、 主队列 2、 全局队列 3 、 自定义队列(串行队列还是并行队列)
(1)主队列:获取朱队列生成一个串行的对列 队列里面的Block快按照先进先出的顺序执行实际上就是一个单线程队列

    dispatch_queue_t queue = dispatch_get_main_queue();
  //  网队列里面添加任务
    dispatch_async(queue, ^{
        [temp test];
        NSLog(@"1");
    });
    dispatch_async(queue, ^{
        [temp test];
        NSLog(@"2");
    });
    dispatch_async(queue, ^{
        [temp test];
        NSLog(@"3");
    });

结果显示:


当然根据需要我们也可以设置程序的延迟执行

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"今晚在如家402一起敲代码,好么?");
    });

(2)全局队列 并发执行

    dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(global, ^{
        [temp test];
        NSLog(@"11");
    });
    dispatch_async(global, ^{
        [temp test];
        NSLog(@"22");
    });
    dispatch_async(global, ^{
        [temp test];NSLog(@"33");
    });


重复执行问题
重复执行的任务第一个参数size_t iterations是重复执行的次数dispatch_queue_t queue 是指定的队列

    dispatch_apply(5, global, ^(size_t t) {//相当于int t
        NSLog(@"执行到第%ld次",t);
    });

(3)自定义队列

    //串行队列
    dispatch_queue_t queue = dispatch_queue_create("AAA", DISPATCH_QUEUE_SERIAL);
        dispatch_async(queue, ^{
            [temp test];
            NSLog(@"111");
        });
        dispatch_async(queue, ^{
            [temp test];
            NSLog(@"222");
        });
        dispatch_async(queue, ^{
            [temp test];
            NSLog(@"333");
        });
    //分组任务  返回结果的先后顺序就不是确定的了 
    dispatch_group_t group  = dispatch_group_create();

        dispatch_group_async(group, queue, ^{
            [temp test];
            NSLog(@"1111");
        });
        dispatch_group_async(group, queue, ^{
            [temp test];
            NSLog(@"2222");
        });
        dispatch_group_async(group, queue, ^{
            [temp test];
            NSLog(@"3333");
        });
        //这句话就是一个谦虚的狗做的 拒绝拿第一
        dispatch_group_notify(group, queue, ^{
            NSLog(@"昭哥变成了数学家");
        });
    //障碍执行 执行任务的时候 要是前面还有任务的话就会等其他任务执行完之后在再执行 
该方法创建的任务在执行的时候 会先检查是不是有其他任务正在执行
要是有等待其执行完毕 再进行执行 否则其他任务要等待其执行完毕之后再执行
    dispatch_barrier_sync(queue, ^{
        [temp test];
        NSLog(@"这个叫做障碍执行");
    });

//不争不抢 最后一步执行
    dispatch_group_notify(queue3, queue2, ^{
        NSLog(@"昭哥变成了数学家");
    });

三、子线程回到主线程

简单介绍几种常用子线程回到主线程的方式

//    GCD
    dispatch_async(dispatch_get_main_queue(), ^{
        //在这里面进行主线程任务的操作(UI的刷新)
    });
//    NSObject
//    (1)
    [self performSelectorOnMainThread:@selector(backMainThread) withObject:nil waitUntilDone:YES];
//    (2)
    [self performSelector:@selector(backMainThread) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];

4、模拟购票系统

声明一个全局变量 int count = 10000; 假设10000张票
声明锁 @property(nonatomic,strong)NSLock *lock;并进行初始化

__weak typeof(self)temp = self;
    dispatch_queue_t queue3 = dispatch_queue_create("CCC", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue3, ^{
        for (int i = 0; i < 100; i++) {
            [temp buyTickets];
        }
    });
    dispatch_async(queue3, ^{
        for (int i = 0; i < 100; i++) {
            [temp buyTickets];
        }
    })
防止发生购票冲突 我们使用了互斥锁
-(void)buyTickets{
    //线程互斥
    @autoreleasepool {
        [_lock lock];
        count--;
        NSLog(@"剩余票数%d",count);
        [_lock unlock];
    }
}
(责任编辑:好模板)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
热点内容