8、多线程

作者: MartinCQ | 来源:发表于2017-06-07 21:32 被阅读222次
    • 进程

    是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。一个进程可以包含多个线程,但至少有一个线程。进程间的内存资源是相互独立的。多开会消耗资源

    • 线程

    线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
    一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
    多线程

    • 优点:提高程序执行效率,
    • 缺点:逻辑会比较复杂,会死锁
    • 队列

    iOS中队列分为

    • 串行队列
    • 并行队列
    //并发队列
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT)
    //串行队列
    dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);
    注:队列完全使用完了之后要 release掉  dispatch_release(quequ);
    
    • 任务
    • 同步任务
    • 异步任务
    //异步任务
        dispatch_async(quequ_chuanxing, ^{
           your Code;
        });
    swift 3.0
         DispatchQueue.global().async {
         }
    
    //同步任务
        dispatch_sync(quequ_chuanxing, ^{
            NSLog(@“异步任务”);
        });
    //延时执行
        func function3() {
            let delay = DispatchTime.now() + DispatchTimeInterval.seconds(15)
            DispatchQueue.main.asyncAfter(deadline: delay) {
                self.label?.backgroundColor = UIColor.blue
                print("hhhh")
            }
        }
    
    image.png

    任务属性决定了代码是否在新线程中执行,队列决定了任务的执行顺序

    | 串行队列 | 并行队列
    --- | --- | ---
    同步任务 | 顺序执行,阻塞主线程,不开启新线程 | 顺序执行,阻塞主线程,不开启新线程
    异步任务asyns | 顺序执行,不阻塞主线程,开启新线程(里面的人都都在另一个非主线程中)| 交叉执行,不阻塞新线程,开启新线程(执行任务的每个线程都不一样)


    多线程实现方式

    NSThread 线程声明周期,程序猿自己管理
    GCD c风格
    NSOperation 面向对象,控制任务个数


    dispatch_barrier_async
    void dispatch_barrier_async ( dispatch_queue_t queue, dispatch_block_t block );
    

    一个dispatch barrier 允许在一个并发队列中创建一个同步点。当在并发队列中遇到一个barrier, 他会延迟执行barrier的block,等待所有在barrier之前提交的blocks执行结束。 这时,barrier block自己开始执行。 之后, 队列继续正常的执行操作。
    调用这个函数总是在barrier block被提交之后立即返回,不会等到block被执行。当barrier block到并发队列的最前端,他不会立即执行。相反,队列会等到所有当前正在执行的blocks结束执行。到这时,barrier才开始自己执行。所有在barrier block之后提交的blocks会等到barrier block结束之后才执行。
    这个在globalqueue中无效,因为系统每次分配的全局队列不一定是同一个队列

    线程组
    dispatch_group_t serviceGroup = dispatch_group_create();//创建线程队列
    dispatch_group_enter(serviceGroup);//当前任务加入队列
    dispatch_group_leave(serviceGroup);//当前任务出队列
    
    //当所有任务都出队列之后走的方法
    dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{
     });
    Swift 3.0
    let group = DispatchGroup.init()
    group.enter()
    group.leave()
    group.notify(queue: DispatchQueue.main) {
         print("最终结果")
    }
    
    互斥线程锁

    同一时间,只有一个线程可以访问这个资源

    @synchronized(self.failedURLs) {
       isFailedUrl = [self.failedURLs containsObject:url];
    }
    
    NSOperationQueue 线程队列
     线程队列是用来存在NSOperation的容器,主要用来管理Operation,一个operation添加到Queue中一般就不再需要start了。
    
    创建
         [[NSOperationQueuealloc]init];
    方法
    - (void)addOperation:(NSOperation *)op;//添加一个operation到queue中会立马异步执行
    
    - (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);//添加一组Operation到queue中,wait意思是是否阻塞当前线程,直到里面的线程执行完
    
    - (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);//直接用block创建一个operation,并添加进来
    
    - (void)cancelAllOperations;//取消当前队列所有任务
    
    - (void)waitUntilAllOperationsAreFinished;//阻塞当前线程,知道里面的任务全部完成
    
    属性
          @property (readonly, copy) NSArray<__kindof NSOperation *> *operations;//当前队列中有的operation
          @property (readonly) NSUInteger operationCount NS_AVAILABLE(10_6, 4_0);//当前队列中Operation的数量
          @property NSInteger maxConcurrentOperationCount;//最大并发数量,默认没有限制
          @property (getter=isSuspended) BOOL suspended;//挂起这个队列,只能挂起还没有被执行,正在执行中的不会被暂停
    @property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);
    /*告诉系统你的任务是在做什么操作
          与用户交互的任务,这些任务通常跟UI级别的刷新相关,比如动画,这些任务需要在一瞬间完成
        NSQualityOfServiceUserInitiated
        由用户发起的并且需要立即得到结果的任务,比如滑动scroll view时去加载数据用于后续cell的显示,这些任务通常跟后续的用户交互相关,在几秒或者更短的时间内完成
        NSQualityOfServiceUtility
        一些可能需要花点时间的任务,这些任务不需要马上返回结果,比如下载的任务,这些任务可能花费几秒或者几分钟的时间
        NSQualityOfServiceBackground
        这些任务对用户不可见,比如后台进行备份的操作,这些任务可能需要较长的时间,几分钟甚至几个小时
        NSQualityOfServiceDefault
        优先级介于user-initiated 和 utility,当没有 QoS信息时默认使用,开发者不应该使用这个值来设置自己的任务
    */
         @property (nullable, assign /* actually retain */) dispatch_queue_t underlyingQueue//当前queue的gcdqueue
              @property (class, readonly, strong, nullable) NSOperationQueue *currentQueue NS_AVAILABLE(10_6, 4_0);//类属性,用来与其他线程间通信
         @property (class, readonly, strong) NSOperationQueue *mainQueue NS_AVAILABLE(10_6, 4_0);//类属性,用来与其他线程间通信
    
    NSOperation
     相当于虚类,调用start执行main方法,直接用的话啥也不干,如果使用子类的话,最好把操作写在main方法中,一般operation不加到队列里的话是在主线程执行,如果加入队列会新开线程。
     子类使用的话方法写在main中,不要写在start中,不然其他状态不会自动维护。
    
         - (void)start;//开始方法
         - (void)main;//开始之后执行的方法
    
         //取消方法与判断,当operation已经在执行中时是cancel不了的,但是会改变iscacelled的值,所以在main方法中(如sdwebimage中),才会在很多地方手动判断是否cancel,然后退出线程执行
         @property (readonly, getter=isCancelled) BOOL cancelled;
         - (void)cancel;
        //是否正在执行
    @property (readonly, getter=isExecuting) BOOL executing;
    //是否执行完了
    @property (readonly, getter=isFinished) BOOL finished;
    //是否异步,但是异步却显示0,其实默认是同步,但是加到队列,以及再加一个block会异步
    @property (readonly, getter=isConcurrent) BOOL concurrent; // To be deprecated; use and override 'asynchronous' below
    @property (readonly, getter=isAsynchronous) BOOL asynchronous
    NS_AVAILABLE(10_8, 7_0);
    //是否准备好了
    @property (readonly, getter=isReady) BOOL ready;
    //添加依赖,移除依赖,添加了的话就op进行完了才进行自己
    - (void)addDependency:(NSOperation *)op;
    - (void)removeDependency:(NSOperation *)op;
    @property (readonly, copy) NSArray<NSOperation *> *dependencies;
    //队列优先级
    typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
    NSOperationQueuePriorityVeryLow = -8L,
    NSOperationQueuePriorityLow = -4L,
    NSOperationQueuePriorityNormal = 0,
    NSOperationQueuePriorityHigh = 4,
    NSOperationQueuePriorityVeryHigh = 8
    };
    @property NSOperationQueuePriority queuePriority;
    //执行完成之后调用的block
    @property (nullable, copy) void (^completionBlock)(void) NS_AVAILABLE(10_6, 4_0);
    //阻塞当前线程
    - (void)waitUntilFinished NS_AVAILABLE(10_6, 4_0);
    //线程优先级 0 - 1
    @property double threadPriority NS_DEPRECATED(10_6, 10_10, 4_0, 8_0);
    //告诉系统这个线程用来干嘛
    @property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);
    //名字
    @property (nullable, copy) NSString *name NS_AVAILABLE(10_10, 8_0);
    
    NSBlockOperation
    + (instancetype)blockOperationWithBlock:(void (^)(void))block;//初始化方法
     - (void)addExecutionBlock:(void (^)(void))block;//添加block会异步新开一个线程
     @property (readonly, copy) NSArray<void (^)(void)> *executionBlocks;//已经添加了的block。
    
    NSInvocationOperation
       //初始化方法
     - (nullableinstancetype)initWithTarget:(id)target selector:(SEL)sel object:(nullableid)arg;
     - (instancetype)initWithInvocation:(NSInvocation *)inv NS_DESIGNATED_INITIALIZER;
    
     @property (readonly, retain) NSInvocation *invocation;
     //返回值?
     @property (nullable, readonly, retain) id result;
    

    两个其实相当于已经封装好了的Operation

    相关文章

      网友评论

        本文标题:8、多线程

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