2019-08-30

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 本文用来介绍 iOS 多线程中 GCD 的相关知识以及使用方法。这大概是史上最详细、清晰的关于 GCD 的详细讲...
    花花世界的孤独行者阅读 494评论 0 1
  • GCD简介 Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法...
    哦累哇滚筒洗衣机阅读 1,193评论 1 2
  • GCD有三种queue main queue: 主线程队列。是一个串行队列。一般用来更新UI。 global qu...
    FreeBreath阅读 601评论 0 0
  • GCD 队列组:dispatch_group 有时候我们会有这样的需求:分别异步执行多个耗时任务,当多个耗...
    gpylove阅读 473评论 0 0
  • 一直想发表自己得第一篇文章,无奈自己是一个中度懒癌患者。就自己认为在前端开发中遇到的一些小问题和自己旁听到得一些知...
    Joe_God阅读 261评论 0 4