2019-08-30

2019-11-19  本文已影响0人  bacon_iOS

前几天,同事多线程访问sqlite的时候遇到一个问题,我也跟着看了一下,这几天又刚好看了一些相关的博文,发现一个问题,所以在此记录一下。

先展示代码如下:

    dispatch_queue_t q = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    for (NSUInteger i = 0; i < 10; i++) {
        
    }

以下是日志打印

2019-08-30 16:34:39.999006+0800 odinDomain[57322:1491164] current thread = <NSThread: 0x600000464a80>{number = 5, name = (null)}, index = 0
2019-08-30 16:34:39.999211+0800 odinDomain[57322:1491164] current thread = <NSThread: 0x600000464a80>{number = 5, name = (null)}, index = 1
2019-08-30 16:34:39.999977+0800 odinDomain[57322:1491164] current thread = <NSThread: 0x600000464a80>{number = 5, name = (null)}, index = 2
2019-08-30 16:34:40.000368+0800 odinDomain[57322:1491164] current thread = <NSThread: 0x600000464a80>{number = 5, name = (null)}, index = 3
2019-08-30 16:34:40.001670+0800 odinDomain[57322:1491164] current thread = <NSThread: 0x600000464a80>{number = 5, name = (null)}, index = 4
2019-08-30 16:34:40.001950+0800 odinDomain[57322:1491164] current thread = <NSThread: 0x600000464a80>{number = 5, name = (null)}, index = 5
2019-08-30 16:34:40.002119+0800 odinDomain[57322:1491164] current thread = <NSThread: 0x600000464a80>{number = 5, name = (null)}, index = 6
2019-08-30 16:34:40.002254+0800 odinDomain[57322:1491164] current thread = <NSThread: 0x600000464a80>{number = 5, name = (null)}, index = 7
2019-08-30 16:34:40.002762+0800 odinDomain[57322:1491164] current thread = <NSThread: 0x600000464a80>{number = 5, name = (null)}, index = 8
2019-08-30 16:34:40.002905+0800 odinDomain[57322:1491164] current thread = <NSThread: 0x600000464a80>{number = 5, name = (null)}, index = 9

代码是在主线程执行的,从日志可以看出,串行队列异步执行任务,会新建一个线程,然后串行队列的任务会在新建的线程里面,按照加入的顺序执行,这与我们预期的效果是一样的。

现在将代码改动 如下

    dispatch_queue_t q = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    
    for (NSUInteger i = 0; i < 10; i++) {
        NSLog(@"start request index = %@", @(i));
        [ODMHttp post:@"http://192.168.124.11:5000/odindomain" parameters:@{@"index": @(i)} success:^(id  _Nullable responseObject) {
            NSLog(@"callback thread = %@, index = %@", NSThread.currentThread, @(i));
            dispatch_async(q, ^{
                NSLog(@"async thread = %@, index = %@", NSThread.currentThread, @(i));
            });
        } failure:^(NSError * _Nullable error) {}];
    }

打印的日志如下:

17:14:37.7034 callback thread = <NSThread: 0x600000279880>{number = 4, name = (null)}, index = 1
17:14:37.7046 async thread = <NSThread: 0x600000279880>{number = 4, name = (null)}, index = 1
17:14:37.7108 callback thread = <NSThread: 0x60000027cf00>{number = 5, name = (null)}, index = 2
17:14:37.7116 callback thread = <NSThread: 0x60000027cf00>{number = 5, name = (null)}, index = 0
17:14:37.7117 async thread = <NSThread: 0x600000279880>{number = 4, name = (null)}, index = 2
17:14:37.7127 callback thread = <NSThread: 0x60000027cf00>{number = 5, name = (null)}, index = 3
17:14:37.7128 async thread = <NSThread: 0x600000279880>{number = 4, name = (null)}, index = 0
17:14:37.7138 async thread = <NSThread: 0x600000279880>{number = 4, name = (null)}, index = 3
17:14:37.7457 callback thread = <NSThread: 0x604000460380>{number = 6, name = (null)}, index = 4
17:14:37.7461 async thread = <NSThread: 0x604000460380>{number = 6, name = (null)}, index = 4
17:14:37.7672 callback thread = <NSThread: 0x60000027cf00>{number = 5, name = (null)}, index = 5
17:14:37.7686 callback thread = <NSThread: 0x60000027cf00>{number = 5, name = (null)}, index = 6
17:14:37.7694 async thread = <NSThread: 0x600000279880>{number = 4, name = (null)}, index = 5
17:14:37.7745 async thread = <NSThread: 0x600000279880>{number = 4, name = (null)}, index = 6
17:14:37.7839 callback thread = <NSThread: 0x600000279880>{number = 4, name = (null)}, index = 7
17:14:37.7853 async thread = <NSThread: 0x60000027c300>{number = 7, name = (null)}, index = 7
17:14:37.7928 callback thread = <NSThread: 0x600000279880>{number = 4, name = (null)}, index = 8
17:14:37.7945 async thread = <NSThread: 0x604000460380>{number = 6, name = (null)}, index = 8
17:14:37.7960 callback thread = <NSThread: 0x60000027d8c0>{number = 8, name = (null)}, index = 9
17:14:37.7968 async thread = <NSThread: 0x60000027d8c0>{number = 8, name = (null)}, index = 9

由此可以发现问题,将任务添加到串行队列之后,串行队列在执行任务的时候,并不是在一个线程,从而引发另一个问题,这些任务的执行有两种情况,并发和串行。
因为是任务在不同的线程执行的,所以怀疑可能是并发的执行;
又因为是在串行队列中,所以也可能是串行执行,只不过是自不同线程的里面的执行的。
于是将代码改为如下所示:

@interface ViewController ()

@property (nonatomic, assign) NSInteger counts;

@end

- (void)viewDidLoad {
    [super viewDidLoad];
    self.counts = 1000;
}

- (void)testRequestQueue {
    dispatch_queue_t q = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    
    for (NSUInteger i = 0; i < 100; i++) {
        NSLog(@"start request index = %@", @(i));
        [ODMHttp post:@"http://192.168.124.11:5000/odindomain" parameters:@{@"index": @(i)} success:^(id  _Nullable responseObject) {
            NSLog(@"callback thread = %@, index = %@", NSThread.currentThread, @(i));
            dispatch_async(q, ^{
                self.counts -= 1;
                NSLog(@"async thread = %@, index = %@ counts = %@", NSThread.currentThread, @(i), @(self.counts));
            });
        } failure:^(NSError * _Nullable error) {
            
        }];
    }
}

如果是多线程并发执行任务的话,那么counts打印的顺序应该会是乱序,经过我多次测试,counts的打印都是顺序的。

再者如果在打印count之前再添加一句代码

[NSThread sleepForTimeInterval:3];

那么会发现结果很有意思,所有的任务的执行又放在同一个线程里面,并且是串行执行的。

由以上的测试的结果,可以得出一个粗略的结论,串行队列可以保证队列里的任务是串行执行的,但是不能保证这些任务是在同一个线程里面执行 。这里面涉及到iOS对线程复用的知识,还未深究。

上一篇下一篇

猜你喜欢

热点阅读