zoukankan      html  css  js  c++  java
  • iOS开发之多线程(NSThread、NSOperation、GCD)

    整理一些多线程相关的知识。

    并行 & 并发

    1、并行:并行是相对于多核而言的,几个任务同时执行。
    2、并发:并发是相对于单核而言的,几个任务之间快速切换运行,看起来像是“同时”发生的一样

    NSThread

    优点:轻量级
    缺点:需要手动管理线程活动,如生命周期、线程同步、睡眠等。
    搭配runloop实现常驻线程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun) object:nil];
    [thread start];
    - (void)threadRun {
    @autoreleasepool {
    NSLog(@"threadRun");
    // NSTimer *timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(timeTask) userInfo:nil repeats:YES];
    // [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(timeTask) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] run];
    }
    }
    - (void)timeTask {
    NSLog(@"timeTask:%@",[NSThread currentThread]);
    }

    NSOperation & NSOperationQueue

    NSOperation

    NSOperation 是一个抽象类,只能使用它的自类来进行操作。系统为我们创建了两个子类NSInvocationOperation & NSBlockOperation。
    直接使用这两个类执行任务,系统不会创建子线程,而是在当前线程执行任务。NSBlockOperation 使用 addExecutionBlock方法的任务是在多线程执行的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //NSInvocationOperation
    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation) object:nil];
    [invocationOperation start];
    //NSBlockOperation
    NSBlockOperation * blockOperation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"blockOperation:%@",[NSThread currentThread]);
    }];
    //这里面的任务是多线程执行的
    [blockOperation addExecutionBlock:^{
    NSLog(@"addExecutionBlock:%@",[NSThread currentThread]);
    }];
    [blockOperation start];
    - (void)invocationOperation {
    NSLog(@"invocationOperation:%@",[NSThread currentThread]);
    }
    //invocationOperation:<NSThread: 0x60800007e1c0>{number = 1, name = main}
    //blockOperation:<NSThread: 0x60800007e1c0>{number = 1, name = main}
    //addExecutionBlock:<NSThread: 0x608000078800>{number = 3, name = (null)}

    NSOperationQueue

    //主队列,任务在主线程执行,一般用于更新UI的时候使用。
    NSOperationQueue queue = [NSOperationQueue mainQueue];
    //子队列,任务在子线程执行,用于处理耗时任务。
    NSOperationQueue
    queue = [[NSOperationQueue alloc] init];

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
    //NSInvocationOperation
    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation) object:nil];
    //NSBlockOperation
    NSBlockOperation * blockOperation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"blockOperation:%@",[NSThread currentThread]);
    }];
    [operationQueue addOperation:invocationOperation];
    [operationQueue addOperation:blockOperation];
    - (void)invocationOperation {
    NSLog(@"invocationOperation:%@",[NSThread currentThread]);
    }
    // invocationOperation:<NSThread: 0x60c00046b940>{number = 4, name = (null)}
    // blockOperation:<NSThread: 0x60800026b580>{number = 3, name = (null)}

    也可以直接添加block

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
    [operationQueue addOperationWithBlock:^{
    NSLog(@"%@",[NSThread currentThread]);
    }];
    [operationQueue addOperationWithBlock:^{
    NSLog(@"%@",[NSThread currentThread]);
    }];
    [operationQueue addOperationWithBlock:^{
    NSLog(@"%@",[NSThread currentThread]);
    }];
    // <NSThread: 0x6080002637c0>{number = 4, name = (null)}
    // <NSThread: 0x60c0002667c0>{number = 5, name = (null)}
    // <NSThread: 0x60000047b2c0>{number = 3, name = (null)}

    可以通过 maxConcurrentOperationCount 来控制最大并发数,当最大并发数为1时,就相当于串行队列

    NSOperation添加依赖关系
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
    //NSBlockOperation
    NSBlockOperation * blockOperation0 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"blockOperation0:%@",[NSThread currentThread]);
    }];
    NSBlockOperation * blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
    sleep(1);
    NSLog(@"blockOperation1:%@",[NSThread currentThread]);
    }];
    //blockOperation0 依赖 blockOperation1,只有在 blockOperation1 执行完成才能执行 blockOperation0
    [blockOperation0 addDependency:blockOperation1];
    [operationQueue addOperation:blockOperation0];
    [operationQueue addOperation:blockOperation1];
    //blockOperation1:<NSThread: 0x600000269c80>{number = 3, name = (null)}
    //blockOperation0:<NSThread: 0x60c000479040>{number = 4, name = (null)}

    注意:NSOperationQueue 是非线程安全的,多个线程访问统一资源时,需要加锁。

    1
    2
    3
    4
    5
    self.lock = [[NSLock alloc] init];
    [self.lock lock];
    //不能同时访问的资源
    [self.lock unlock];

    GCD

    创建队列,然后再往队列添加任务。也可以直接使用系统创建的队列。

    1
    2
    3
    4
    5
    6
    7
    8
    //创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.vhuichen.queue", DISPATCH_QUEUE_SERIAL);
    //创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("com.vhuichen.queue", DISPATCH_QUEUE_CONCURRENT);
    //获取主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    //获取全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    创建同步、异步任务

    1
    2
    3
    4
    5
    6
    7
    dispatch_sync(queue, ^{
    //同步执行
    });
    // 异步执行任务创建方法
    dispatch_async(queue, ^{
    //异步执行
    });

    GCD常用方法

    dispatch_barrier

    只有当添加在dispatch_barrier前面的任务完成了,才开始执行dispatch_barrier任务。
    有两种方式:dispatch_barrier_syncdispat 大专栏  iOS开发之多线程(NSThread、NSOperation、GCD)ch_barrier_async

    dispatch_barrier_sync
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    dispatch_queue_t queue = dispatch_queue_create("com.vhuichen.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
    NSLog(@"task0.....");
    sleep(1);
    });
    dispatch_async(queue, ^{
    NSLog(@"task1.....");
    sleep(1);
    });
    dispatch_barrier_sync(queue, ^{
    NSLog(@"task2.....");
    sleep(5);
    });
    NSLog(@"test");
    dispatch_async(queue, ^{
    NSLog(@"task3.....");
    sleep(2);
    });
    dispatch_async(queue, ^{
    NSLog(@"task4.....");
    sleep(1);
    });
    //task0.....
    //task1.....
    //task2.....
    //test....
    //task3.....
    //task4.....
    //只有当task0、task1 执行完才会执行tast2.
    //task2 执行完才会往下执行。
    //test 执行完后,才会把task3、task4 加进队列.
    dispatch_barrier_async
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    dispatch_queue_t queue = dispatch_queue_create("com.vhuichen.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
    NSLog(@"task0.....");
    sleep(1);
    });
    dispatch_async(queue, ^{
    NSLog(@"task1.....");
    sleep(1);
    });
    dispatch_barrier_async(queue, ^{
    NSLog(@"task2.....");
    sleep(5);
    });
    NSLog(@"test");
    dispatch_async(queue, ^{
    NSLog(@"task3.....");
    sleep(2);
    });
    dispatch_async(queue, ^{
    NSLog(@"task4.....");
    sleep(1);
    });
    //test....
    //task1.....
    //task0.....
    //task2.....
    //task3.....
    //task4.....
    //test、task0、task1 并发执行。
    //task0、task1 执行完才会执行tast2.
    //tast2 执行完才会执行tast3、tast4.
    dispatch_after
    1
    2
    3
    4
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    NSLog(@"dispatch_after task...");
    });
    //dispatch_after 会在到了指定的时间之后,将才将任务加到相应的队列中。
    dispatch_once

    一般会以这种形式出现

    1
    2
    3
    4
    5
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    NSLog(@"dispatch_once task...");
    });
    //block里面的任务只会执行一次。
    dispatch_apply
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    dispatch_queue_t queue = dispatch_queue_create("com.vhuichen.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_apply(10, queue, ^(size_t index) {
    NSLog(@"%zu",index);
    });
    NSLog(@"end");
    // 0
    // 1
    // 3
    // 2
    // 4
    // 5
    // 6
    // 7
    // 8
    // 9
    // end
    // dispatch_apply 会等待所有的任务完成了,才会往下执行。
    dispatch_semaphore

    可以用于线程同步、线程加锁、控制并发线程数量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //实现同步请求
    let semaphoreSignal = DispatchSemaphore(value: 0)
    ZBDepthAPI.GET(market: market.name!, succeed: { (depthModel) in
    //......
    semaphoreSignal.signal()
    }) { (error) in
    //......
    semaphoreSignal.signal()
    }
    semaphoreSignal.wait()
    dispatch_group

    当需要同时执行多个耗时任务,并且当所有任务执行完后更新UI。那么这时可以使用 dispatch_group 来实现。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_async(group, global, ^{
    NSLog(@"tast0.......");
    });
    NSLog(@"0");
    dispatch_group_async(group, global, ^{
    NSLog(@"tast1.......");
    });
    NSLog(@"1");
    dispatch_group_async(group, global, ^{
    NSLog(@"tast2.......");
    sleep(1);
    });
    NSLog(@"2");
    dispatch_group_enter(group);
    dispatch_async(global, ^{
    NSLog(@"tast00.......");
    dispatch_group_leave(group);
    });
    // 所有任务完成的时候调用
    //dispatch_group_notify(group, global, ^{
    // NSLog(@"tast complete...");
    //});
    //会阻塞当前线程,直到 group 里面的任务全部完成
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    NSLog(@"wait");
    // 异步加入的任务会立即执行
    // dispatch_group_wait会阻塞当前线程,直到 group 里面的任务全部完成
    // dispatch_group_enter & dispatch_group_leave 必须成对出现,相当于 dispatch_group_async

    总结

    当遇到相应场景的时候,知道使用哪种方法比较合理就行了。

  • 相关阅读:
    C# 四种基本排序算法(冒泡排序,插入排序,选择排序,快速排序)外加折半排序
    jQuery ajax serialize() 方法
    关于问问题
    VIM键位图
    Highcharts选项配置详细说明文档
    awk处理文件内容格式
    【转】如何写出高性能SQL语句
    PHP合并、追加与连接数组
    如何选择web开发语言
    PHP 数据类型验证和获取
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12327412.html
Copyright © 2011-2022 走看看