如何在多个线程中执行任务比在主线程上顺序执行慢100倍?

鸭子

我有另一个问题,我曾问过有关使用Grand Central Dispatch将代码从顺序处理转换为并行处理的问题。

我将复制问题文本以使事情变得容易...


我有一个必须通过20个测试的NSNumbers数组。如果一项测试失败,则该数组无效;如果所有测试通过,则该数组无效。我正在尝试以这样的方式进行操作:一旦第一次失败发生,它就会停止进行其余的测试。如果第三次测试失败,则停止评估其他测试。

每个单独的测试在失败时都返回YES,在没有问题时返回NO。

我正在尝试将已有的代码(即串行处理)转换为具有中央集中调度的并行处理,但是我无法将其束之高阁。

这就是我所拥有的。

首先定义要进行的测试。该数组用于运行测试。

#define TESTS  @[         \
    @"averageNotOK:",     \
    @"numbersOverRange:", \
    @"numbersUnderRange:",\
    @"numbersForbidden:", \
    // ... etc etc
    @"numbersNotOnCurve:"]


- (BOOL) numbersPassedAllTests:(NSArray *)numbers {

  NSInteger count = [TESTS count];

  for (int i=0; i<count; i++) {

    NSString *aMethodName = TESTS[i];

        SEL selector = NSSelectorFromString(aMethodName);

        BOOL failed = NO;

        NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];

        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
        [invocation setSelector:selector];
        [invocation setTarget:self];
        [invocation setArgument:&numbers atIndex:2];
        [invocation invoke];


        [invocation getReturnValue:&failed];

        if (failed) {
          return NO;
        }
  }
  return YES;

}

这可以完美地工作,但是可以顺序执行测试。

在用户的帮助下处理代码后,我使用中央集中调度程序获得了以下代码:

- (BOOL) numbersPassedAllTests:(NSArray *)numbers {

  volatile __block int32_t hasFailed = 0;

  NSInteger count = [TESTS count];

  __block NSArray *numb = [[NSArray alloc] initWithArray:numbers];

  dispatch_apply(
                 count,
                 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
                 ^(size_t index)
                 {
                   // do no computation if somebody else already failed
                   if(hasFailed) {
                    return;
                   }


                   SEL selector = NSSelectorFromString(TESTS[index]);

                   BOOL failed = NO;

                   NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];

                   NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
                   [invocation setSelector:selector];
                   [invocation setTarget:self];
                   [invocation setArgument:&numb atIndex:2];
                   [invocation invoke];

                   [invocation getReturnValue:&failed];

                   if(failed)
                     OSAtomicIncrement32(&hasFailed);
                 });

  return !hasFailed;
}

“活动监视器”显示了似乎正在被更密集地使用的核心,但是此代码比顺序运行的旧代码慢至少100倍!

怎么可能?

如果您要调用的方法很简单,那么创建所有这些线程的开销可能会抵消并发所获得的任何优势。正如《并发编程指南》中的“同时执行循环迭代”部分所述

您应该确保您的任务代码在每次迭代中都进行合理的工作量。与您分派到队列中的任何块或函数一样,安排该代码执行的开销。如果循环的每次迭代仅执行少量工作,则调度代码的开销可能会超过将其分派到队列可能带来的性能收益。如果在测试期间发现这是正确的,则可以使用跨步来增加每次循环迭代期间执行的工作量。跨步时,您可以将原始循环的多个迭代组合到一个块中,并按比例减少迭代计数。例如,如果您最初执行100次迭代,但决定使用4的步幅,则现在从每个块执行4次循环迭代,您的迭代计数为25。循环代码方面的改进。”

与“改进循环代码”的链接通过跨步实现了示例,从而使线程数量与每个线程完成的工作量保持平衡。您需要做一些实验才能找到适合您方法的平衡点,然后尝试不同的跨度值,直到获得最佳性能。

在与CPU绑定的进程的实验中,我发现执行两个线程时获得了巨大的收益,但此后却有所减少。它可能会根据您所调用的方法中的内容而有所不同。


顺便问一下,您要调用的这些方法在做什么?如果您执行任何需要主线程的操作(例如,UI更新),那也会使结果产生偏差。为了进行比较,我建议您以串行示例为例,并将其分发到后台队列(作为单个任务),并查看通过这种方式获得的性能。这样,您就可以区分主队列和后台队列的相关问题,以及我上面讨论的线程过多的开销问题。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在剩余线程完成工作的同时执行任务

来自分类Dev

在当前线程上执行任务

来自分类Dev

在新线程中执行任务时冻结JavaFX UI

来自分类Dev

在主线程上执行异步任务的最佳方法

来自分类Dev

在主线程中执行Action <>

来自分类Dev

在主线程中执行Action <>

来自分类Dev

Java仅用于2台计算机的多线程,如何在主线程中执行

来自分类Dev

Java仅用于2台计算机的多线程,如何在主线程中执行

来自分类Dev

如何在Qt主线程中正确执行GUI操作?

来自分类Dev

如何在主线程执行期间更改控件属性?

来自分类Dev

确保在主线程上执行完成块

来自分类Dev

需要在主线程上执行什么

来自分类Dev

如何在UI线程上执行冗长的任务期间强制执行UI更新

来自分类Dev

如何保证GPars线程池中任务的执行/显示顺序?

来自分类Dev

在(clojure的内部)线程池中执行任务的惯用方式?

来自分类Dev

使用线程池执行任务时出现RejectedExecutionException:JAVA

来自分类Dev

如何从任务在主线程上运行语句

来自分类Dev

使用boost :: future :: then在主线程中执行

来自分类Dev

使用boost :: future :: then在主线程中执行

来自分类Dev

如何在后台执行任务?

来自分类Dev

如何在Android中的非UI线程上执行延迟

来自分类Dev

如何授予Boost Pool访问GSL矩阵以执行任务的线程

来自分类Dev

在后台执行任务的最佳方法是什么(application_start中的线程或调用方法)?

来自分类Dev

在后台执行任务的最佳方法是什么(application_start中的线程或调用方法)?

来自分类Dev

ActiveAndroid .save()操作是在主线程上执行还是异步执行?

来自分类Dev

ActiveAndroid .save()操作是在主线程上执行还是异步执行?

来自分类Dev

Java:如何在独立于主线程的命令窗口中打开新线程的执行?

来自分类Dev

在单独的ThreadPool中执行某些后台任务,以避免饿死于在主线程中执行的关键任务

来自分类Dev

如何在iOS中执行多线程?

Related 相关文章

  1. 1

    如何在剩余线程完成工作的同时执行任务

  2. 2

    在当前线程上执行任务

  3. 3

    在新线程中执行任务时冻结JavaFX UI

  4. 4

    在主线程上执行异步任务的最佳方法

  5. 5

    在主线程中执行Action <>

  6. 6

    在主线程中执行Action <>

  7. 7

    Java仅用于2台计算机的多线程,如何在主线程中执行

  8. 8

    Java仅用于2台计算机的多线程,如何在主线程中执行

  9. 9

    如何在Qt主线程中正确执行GUI操作?

  10. 10

    如何在主线程执行期间更改控件属性?

  11. 11

    确保在主线程上执行完成块

  12. 12

    需要在主线程上执行什么

  13. 13

    如何在UI线程上执行冗长的任务期间强制执行UI更新

  14. 14

    如何保证GPars线程池中任务的执行/显示顺序?

  15. 15

    在(clojure的内部)线程池中执行任务的惯用方式?

  16. 16

    使用线程池执行任务时出现RejectedExecutionException:JAVA

  17. 17

    如何从任务在主线程上运行语句

  18. 18

    使用boost :: future :: then在主线程中执行

  19. 19

    使用boost :: future :: then在主线程中执行

  20. 20

    如何在后台执行任务?

  21. 21

    如何在Android中的非UI线程上执行延迟

  22. 22

    如何授予Boost Pool访问GSL矩阵以执行任务的线程

  23. 23

    在后台执行任务的最佳方法是什么(application_start中的线程或调用方法)?

  24. 24

    在后台执行任务的最佳方法是什么(application_start中的线程或调用方法)?

  25. 25

    ActiveAndroid .save()操作是在主线程上执行还是异步执行?

  26. 26

    ActiveAndroid .save()操作是在主线程上执行还是异步执行?

  27. 27

    Java:如何在独立于主线程的命令窗口中打开新线程的执行?

  28. 28

    在单独的ThreadPool中执行某些后台任务,以避免饿死于在主线程中执行的关键任务

  29. 29

    如何在iOS中执行多线程?

热门标签

归档