酷酷的哀殿


  • 首页

  • 技术

  • 笔记

  • 杂记

  • Todo

  • 关于

  • 搜索
close

GCD 的线程数量限制分析

时间: 2021-03-21   |   阅读: 1206 字 ~3分钟

前言

有网友在交流群反馈自己遇到一个“奇怪”的面试题:“GCD 最多开多少线程?”

本文,会通过实际的 Demo 测试不同场景下的情况

测试环境

iOS 14.3

测试代码

全局队列 - CPU 繁忙

第一个测试 case,我们通过 dispatch_get_global_queue(0, 0) 获取一个默认的全局队列,并通过 while 模拟 CPU 繁忙。

 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
38
39
40
41

+ (void)printThreadCount {
    kern_return_t kr = { 0 };
    thread_array_t thread_list = { 0 };
    mach_msg_type_number_t thread_count = { 0 };
    kr = task_threads(mach_task_self(), &thread_list, &thread_count);
    if (kr != KERN_SUCCESS) {
        return;
    }
    NSLog(@"线程数量:%@", @(thread_count));

    kr = vm_deallocate( mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t) );
    if (kr != KERN_SUCCESS) {
        return;
    }
    return;
}

+ (void)test1 {
    NSMutableSet<NSThread *> *set = [NSMutableSet set];
    for (int i=0; i < 1000; i++) {
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        dispatch_async(queue, ^{
            NSThread *thread = [NSThread currentThread];
            [set addObject:[NSThread currentThread]];
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"开始:%@", thread);
                NSLog(@"GCD 创建的线程数量:%lu",(unsigned long)set.count);
                [self printThreadCount];
            });

            NSDate *date = [NSDate dateWithTimeIntervalSinceNow:10];
            long i=0;
            while ([date compare:[NSDate date]]) {
                i++;
            }
            [set removeObject:thread];
            NSLog(@"结束:%@", thread);
        });
    }
}

经过测试:线程数量是 2

全局队列 - CPU 空闲

第二份代码,我们通过 [NSThread sleepForTimeInterval:10]; 模拟 CPU 空闲 进行测试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
+ (void)test2 {
    NSMutableSet<NSThread *> *set = [NSMutableSet set];
    for (int i=0; i < 1000; i++) {
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        dispatch_async(queue, ^{
            NSThread *thread = [NSThread currentThread];
            [set addObject:[NSThread currentThread]];
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"开始:%@", thread);
                NSLog(@"GCD 创建的线程数量:%lu",(unsigned long)set.count);
                [self printThreadCount];
            });
            // 当前线程睡眠 10 秒
            [NSThread sleepForTimeInterval:10];
            [set removeObject:thread];
            NSLog(@"结束:%@", thread);
            return;
        });
    }
}

经过测试,线程数量最高是 64 个

自建队列 - CPU 繁忙

现在,我们看看 自建队列 - CPU 繁忙 的表现,本例会模拟大部分 APP 的场景,不同业务方都创建单独的队列管理自己的任务

 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

+ (void)test3 {
    NSMutableSet<NSThread *> *set = [NSMutableSet set];
    for (int i=0; i < 1000; i++) {
        const char *label = [NSString stringWithFormat:@"label-:%d", i].UTF8String;
        NSLog(@"创建:%s", label);
        dispatch_queue_t queue = dispatch_queue_create(label, DISPATCH_QUEUE_SERIAL);
        dispatch_async(queue, ^{
            NSThread *thread = [NSThread currentThread];
            [set addObject:[NSThread currentThread]];

            dispatch_async(dispatch_get_main_queue(), ^{
                static NSInteger lastCount = 0;
                if (set.count <= lastCount) {
                    return;
                }
                lastCount = set.count;
                NSLog(@"开始:%@", thread);
                NSLog(@"GCD 创建的线程数量:%lu",(unsigned long)set.count);
                [self printThreadCount];
            });

            NSDate *date = [NSDate dateWithTimeIntervalSinceNow:10];
            long i=0;
            while ([date compare:[NSDate date]]) {
                i++;
            }
            [set removeObject:thread];
            NSLog(@"结束:%@", thread);
        });
    }
}

经过测试,GCD 创建的线程数量最高是 512 个

自建队列 - CPU 空闲

 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

+ (void)test4 {
    NSMutableSet<NSThread *> *set = [NSMutableSet set];
    for (int i=0; i < 10000; i++) {
        const char *label = [NSString stringWithFormat:@"label-:%d", i].UTF8String;
        NSLog(@"创建:%s", label);
        dispatch_queue_t queue = dispatch_queue_create(label, DISPATCH_QUEUE_SERIAL);
        dispatch_async(queue, ^{
            NSThread *thread = [NSThread currentThread];

            dispatch_async(dispatch_get_main_queue(), ^{
                [set addObject:thread];
                static NSInteger lastCount = 0;
                if (set.count <= lastCount) {
                    return;
                }
                lastCount = set.count;
                NSLog(@"开始:%@", thread);
                NSLog(@"GCD 创建的线程数量:%lu",(unsigned long)set.count);
                [self printThreadCount];
            });

            [NSThread sleepForTimeInterval:10];
            dispatch_async(dispatch_get_main_queue(), ^{
                [set removeObject:thread];
                NSLog(@"结束:%@", thread);
            });
        });
    }
}

自建队列 - CPU 空闲 创建的线程数量最高是 512 个

结论

经过测试,GCD 的全局队列会自动将线程数量限制在一个比较合理的数量。与之相比,自建队列创建的线程数量会偏大。

考虑到线程数量过大会导致 CPU 调度成本上涨。

所以,建议小型 APP 尽量使用全局队列管理任务;大型 APP 可以根据自己的实际情况决定适合自己的方案。

#GCD# #线程#
Xcode 新构建系统 与 cmake 的兼容性解决方案
Objective-C 与 泛型
  • 文章目录
  • 站点概览
酷酷的哀殿

酷酷的哀殿

单身狗

74 日志
83 标签
    • 前言
    • 测试环境
    • 测试代码
      • 全局队列 - CPU 繁忙
      • 全局队列 - CPU 空闲
      • 自建队列 - CPU 繁忙
      • 自建队列 - CPU 空闲
    • 结论
© 2021 酷酷的哀殿 京ICP备18052541号-2
Powered by - Hugo v0.80.0
Theme by - NexT
0%