美文网首页
2019-08-30

2019-08-30

作者: bacon_iOS | 来源:发表于2019-11-19 19:22 被阅读0次

    前几天,同事多线程访问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对线程复用的知识,还未深究。

    相关文章

      网友评论

          本文标题:2019-08-30

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