将代码转换为Grand Central Dispatch

时间:2014-05-06 22:32:44

标签: cocoa grand-central-dispatch

我有一组NSNumbers必须通过20次测试。如果一个测试失败,那么如果所有测试都通过,则数组无效,则数组有效。我试图以第一次失败发生时停止进行剩余测试的方式进行。如果第3次测试失败,则停止评估其他测试。

我正在尝试将我所拥有的串行处理代码转换为使用大型中央调度的并行处理,但我无法将其包围起来。

这就是我所拥有的。

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

每个单独的测试在失败时返回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;

}

这项工作非常完美,但是按顺序执行测试。

如何根据需要并行执行少量测试来执行这些测试?

1 个答案:

答案 0 :(得分:0)

我认为你已经发现dispatch_apply这是一个微不足道的平行线。你已经意识到它不能提前退出。因此问题。

我担心答案是你需要为自己做一些簿记,但幸运的是它不应该太难。为了避免重复你所拥有的,假装我把你的循环中的东西变成了:

BOOL failedTest(int);

所以你的串行循环如下:

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

    if(failedTest(i))
      return NO;
}

return YES;

然后你可能会这样做:

#import <libkern/OSAtomic.h>

volatile __block int32_t hasFailed = 0;
dispatch_apply(
    count, 
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), 
    ^(size_t i)
    {
        // do no computation if somebody else already failed
        if(hasFailed) return;
        if(failedTest(i))
            OSAtomicIncrement32(&hasFailed);
    });

return !hasFailed;

所以它会继续开始测试,直到其中一个先前失败。 OSAtomicIncrement32只需确保原子性而无需互斥锁。它通常会变成廉价的单指令。你只需使用BOOL就可以逃脱,因为原子性并不是一个问题,但为什么不正确呢?

编辑:另外,您可以直接使用@selector并创建一个选择器数组,而不是使用带有字符串数组的NSSelectorFromString来节省查找时间。如果您的测试非常便宜,那么考虑将它们作为部分串行,部分并行,方法是dispatch_apply执行,例如count/10调度,并让每个调度执行10次测试。否则,GCD将仅发出块的count个实例,并且发布具有相关的成本。