squarezw
6/13/2014 - 6:05 AM

Thread Queue

Thread Queue

  1. 线程最多同时10 并行线程 (DISPATCH_QUEUE_CONCURRENT)

    当你每个线程都开一个 while(true) {} 循环 你再开并行线程时就不能被分配了。这个时候CPU应该是在 500% 以上

//
//  ViewController.m
//  MultiThread
//
//  Created by apple on 14-6-12.
//  Copyright (c) 2014年 square. All rights reserved.
//

#import "ViewController.h"

@implementation NSThread (ThreadGetIndex)

-(NSString*)getThreadNum
{
    NSString * description = [ self description ] ;
    
    NSRange range;
    range.location = [description length] - 5;
    range.length = 4;
    
    return [description substringWithRange:range];
}

@end

@implementation ViewController
{
    UILabel *labelA;
    UILabel *labelB;
    UILabel *labelC;
    
    UILabel *heapLabel;
    int heapData;
    
    BOOL startD;
    BOOL pageStillLoading;
    UIProgressView *progress;
}

- (void)viewDidAppear:(BOOL)animated
{
    [self exampleWithBlock];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 50, 150, 30)];
    [button setTitle:@"开启RunLoop下载" forState:UIControlStateNormal];
    [button setBackgroundColor:[UIColor blueColor]];
    [button addTarget:self action:@selector(start:) forControlEvents:UIControlEventTouchUpInside];
    
    progress = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, 320, 20)];
    [progress setTrackTintColor:[UIColor redColor]];
    [progress setHidden:YES];
    
    heapLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 80, 150, 50)];
    heapLabel.text = [NSString stringWithFormat:@"heap data: %d", heapData];
    
    labelA = [[UILabel alloc] initWithFrame:CGRectMake(0, 150, 300, 50)];
    labelB = [[UILabel alloc] initWithFrame:CGRectMake(0, 250, 300, 50)];
    labelC = [[UILabel alloc] initWithFrame:CGRectMake(0, 350, 300, 50)];
    labelA.font = [UIFont systemFontOfSize:12];
    
    [self.view addSubview:heapLabel];
    [self.view addSubview:labelA];
    [self.view addSubview:labelB];
    [self.view addSubview:labelC];
    [self.view addSubview:button];
    [self.view addSubview:progress];
    
//    [self multiWithThread];
//    [self multiWithDispatch];
    [self multiWithOperation];
    
}

/**
 *  Thread
 */
- (void)multiWithThread
{
    [NSThread detachNewThreadSelector:@selector(threadA) toTarget:self withObject:nil];
    [NSThread detachNewThreadSelector:@selector(threadB) toTarget:self withObject:nil];
    [NSThread detachNewThreadSelector:@selector(threadC) toTarget:self withObject:nil];
}

/**
 *  Operation
 *
 *  Task:
 *      A -> B
 *              -> D
 *           C
 *
 */
- (void)multiWithOperation
{

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSInvocationOperation *opA = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(threadA) object:nil];
    NSInvocationOperation *opB = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(threadB) object:nil];
    
    NSBlockOperation *opC = [NSBlockOperation blockOperationWithBlock:^{
        sleep(2);
        [self performSelectorOnMainThread:@selector(showContentWithLabelC:) withObject:[NSString stringWithFormat:@"执行第1次操作,线程:%@",[self threadName]] waitUntilDone:NO];
    }];
    [opC addExecutionBlock:^{
        sleep(3);
        [self performSelectorOnMainThread:@selector(showContentWithLabelC:) withObject:[NSString stringWithFormat:@"又执行了一次操作,线程:%@",[self threadName]] waitUntilDone:NO];
    }];
    
    NSBlockOperation *opD = [NSBlockOperation blockOperationWithBlock:^{
        startD = YES;
//        while (startD) {
//            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
//            if ([opA isFinished] && [opB isFinished]) {
                NSLog(@"终于到我了...");
//                startD = NO;
//            }
//        }
    }];

    [opB addDependency:opA];
//    [opB setCompletionBlock:^{
//        [queue addOperation:opD];
//    }];
    
    [opD addDependency:opB];
    [opD addDependency:opC];
    
    [queue addOperation:opA];
    [queue addOperation:opB];
    [queue addOperation:opC];
    [queue addOperation:opD];
    
}

/**
 *  Dispatch
 */
- (void)multiWithDispatch
{
    // dispatch_queue_create
    // ----
    // this is serial, run task by order
    //
    dispatch_queue_t dis_queue = dispatch_queue_create("com.multiThread.taskA", DISPATCH_QUEUE_SERIAL);
    dispatch_async(dis_queue, ^{
        [self threadA];
    });
    dispatch_async(dis_queue, ^{
        [self threadB];
    });
    
    dispatch_after(DISPATCH_TIME_NOW, dis_queue, ^{
        NSLog(@"终于到我了......");
    });
    
    //
    // dispatch group
    //
//    dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//    dispatch_queue_t queue2 = dispatch_queue_create("com.multiThread.taskB", DISPATCH_QUEUE_SERIAL);
//    dispatch_group_t group = dispatch_group_create();
//    // Add a task to the group
//    dispatch_group_async(group, queue1, ^{
//        [self threadA];
//    });
//    
//    dispatch_group_async(group, queue2, ^{
//        [self threadB];
//    });
//
//    dispatch_group_wait(group, DISPATCH_TIME_NOW);
    
    // dispatch_get_global_queue
    // --
    // this is concurrent, run task by async
    //
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self threadC];
    });
    
    // ------
    // go to work after delay 5 sec
    // will stuck main thread
    //
//    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//        [self threadC];
//    });
}

#pragma mark - threads

- (NSString*)threadName
{
    return [NSString stringWithFormat:@"%@", [[NSThread currentThread] getThreadNum]];
}

- (void)threadA
{
    @autoreleasepool {
        [NSThread sleepForTimeInterval:1.0f];
    
        for (int i = 0; i < 10000; i++) {
            @autoreleasepool {
                [self performSelectorOnMainThread:@selector(showContentWithLabelA:) withObject:[NSString stringWithFormat:@"Thread A: %@, %d", [self threadName], i] waitUntilDone:YES];
                heapData = i;
            }
        }
    }
}

- (void)threadB
{
    for (int i = 0; i < 10000; i++) {
        @autoreleasepool {
            [self performSelectorOnMainThread:@selector(showContentWithLabelB:) withObject:[NSString stringWithFormat:@"Thread B: %@, %d", [self threadName], i] waitUntilDone:YES];
        }
    }
}

- (void)threadC
{
    for (int i = 0; i < 100000; i++) {
        @autoreleasepool {
            [self performSelectorOnMainThread:@selector(showContentWithLabelC:) withObject:[NSString stringWithFormat:@"Thread C: %@, %d", [self threadName], i] waitUntilDone:YES];
        }
    }
}

- (IBAction)start:(id)sender
{
    pageStillLoading = YES;
    [NSThread detachNewThreadSelector:@selector(runInBackground:) toTarget:self withObject:nil];
    [progress setHidden:NO];
    while (pageStillLoading) {
        NSLog(@"runloop…");
    	[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        NSLog(@"runloop end.");
    }
    [progress setHidden:YES];
}

- (void) runInBackground:(id)arg
{
    @autoreleasepool {
        // Simmulate web page loading
        sleep(5);
        
        // This will not wake up the runloop on main thread!
        pageStillLoading = NO;
        
        // Wake up the main thread from the runloop
//        [self performSelectorOnMainThread:@selector(wakeUpMainThreadRunloop:) withObject:nil waitUntilDone:NO];
    }
}

- (void)wakeUpMainThreadRunloop:(id)arg
{
    NSLog(@"wake up main thread run loop.");
}

#pragma mark - UI
- (void)showContentWithLabelA:(NSString*)text
{
    labelA.text = text;
    heapLabel.text = [NSString stringWithFormat:@"heap data: %d", heapData];
}

- (void)showContentWithLabelB:(NSString*)text
{
    labelB.text = text;
    heapLabel.text = [NSString stringWithFormat:@"heap data:%d", heapData];
}

- (void)showContentWithLabelC:(NSString*)text
{
    labelC.text = text;
    heapLabel.text = [NSString stringWithFormat:@"heap data:%d", heapData];
}

#pragma mark - About Block

- (void)exampleWithBlock
{
    __block int j = 0;
    
    void (^myBlock)(int) = ^(int c){
        j = c;
    };
    
    myBlock(3);
    NSLog(@"%d", j);
}

@end
/*
 * 栅栏
 * Barrier
 *
 * 用来处理并行队列里某些任务必须在稍后执行
 *
 * dispatch_barrier_async
 * dispatch_barrier_async_f
 * dispatch_barrier_sync
 * dispatch_barrier_sync_f
 * 
 * dispatch_barrier_async是异步的,调用后立刻返回,即使block3到了队列首部,也不
 * 会立刻执行,而是等到block1和block2的并行执行完成后才会执行block3,完成后再会
 * 并行运行block4。
 *
 * !!!: 注意这里的queue应该是一个并行队列,而且必须是dispatch_queue_create(label, attr)
 * 创建的自定义并行队列,dispatch_get_global_queue 或主队列都不行,因为主队列也
 * 是串行的,全局队列是不受你控制的。
 *
 */

    dispatch_queue_t queue = dispatch_queue_create("task", DISPATCH_QUEUE_CONCURRENT);  
    
    dispatch_async(queue, ^{  
        NSLog(@"1");  
    });  
    dispatch_async(queue, ^{  
        NSLog(@"2");  
    });  
    dispatch_barrier_async(queue, ^{  
        NSLog(@"我一定第3执行");  
    });  
    dispatch_async(queue, ^{  
        NSLog(@"4");  
    });  
    
/*
 * Thread 
 * dispatch_async(...) 分配一个线程调度
 * dispatch_sync(...) 在当前线程调度,如果当前线程是主线程,那么分配的任务也是在主线程
 * 
 * 简化了 NSOperationQueue 的创建与分配,最终目的同样也是创建 Queue 在不同的线程执行
 *
 * Queue
 * DISPATCH_QUEUE_SERIAL  串行
 * DISPATCH_QUEUE_CONCURRENT 并行
 * 
 * 串行队列所有的Block都由一个线程来执行(同应用主线程一样),而并发队列会把队列
 * 里的Block分发到不同的线程来执行。
 * 
 */


// 当前线程,队列信息, 推荐只在 Debug 环境下使用
dispatch_get_current_queue()

// get queue label
dispatch_queue_get_label(queue)

// 串行队列,顺序执行各自任务
dispatch_queue_create("com.multiThread.taskA", DISPATCH_QUEUE_SERIAL)

// 并行队列,同时执行队列中的任务,推荐!!!
dispatch_queue_create("com.multiThread.taskA", DISPATCH_QUEUE_CONCURRENT)