Mike97
Mike97

Reputation: 605

Slow loop using GCD

I've to run many packages but also some method (70 methods + 40 packages), and I am building _myArray based on what user have selected in the app interface. This is because I can not know what that user will select before press the "start" button, and the app requires that all things follow a predetermined order (_myArray was sorted). The app support OSX since 10.7

-(void)package01 {
}

-(void)package02 {
}

.....

-(void)package40 {

    // also tried with NSTask, but is slow exactly as NSAppleScript (so guess that this is not the problem)

    NSString* package = [_pathToPkg stringByAppendingPathComponent:@"40.pkg"];
    NSAppleScript* runpkg;
    NSString *command = [NSString stringWithFormat:@"/usr/sbin/installer -pkg %@ -target %@", package, _targetOBJ];

    runpkg = [[NSAppleScript alloc] initWithSource:[NSString stringWithFormat:
                                                    @"do shell script \"%@\"", command]];

    [runpkg executeAndReturnError: nil];
}

-(void)oneOfMyMethod {
dispatch_async(_myQueue,
               ^{
                   // some operation
                   dispatch_async(_mymainQueue, ^{/*updating interface here*/});
               });

dispatch_async(_myQueue,
               ^{
                   // more operation
                   dispatch_async(_mymainQueue, ^{/*updating interface here*/});
               });

dispatch_async(_myQueue,
               ^{
                   // ++ operation
                   dispatch_async(_mymainQueue, ^{/*updating interface here*/});
               });


// Here I'm calling the problematic Method:
[self runPackageOrMethod:^(BOOL finished) {
    if(finished){
        [self doOther];
    }
}];

}

// this is pratically the core of the app...
- (void) runPackageOrMethod:(completion) compblock{

    _pathToPkg = @"path/to/the/folder/that/contain/packages";


    dispatch_group_t group = dispatch_group_create();

    @try {
        for (NSString *method in _myArray) {
                    NSArray *descriptions;
                    descriptions = [NSArray arrayWithArray:[METHOD_DESCRIPTION allKeys]]; // Another array that I use to display some info about running pkg or method

                    dispatch_group_async(group,_myQueue, ^ {
                        dispatch_async(_mymainQueue, ^{
                            if ([descriptions containsObject:method] && ![[METHOD_DESCRIPTION objectForKey:method] isEqualToString:@"MUTE"]) {
                                [_displayStore appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"\n- %@\n", [METHOD_DESCRIPTION objectForKey:method]]  attributes:_dispAttr]];
                                [_display scrollToEndOfDocument:self];
                            }
                        });
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
                        dispatch_async(_mymainQueue, ^{[self performSelector:NSSelectorFromString(method)  withObject:nil];});
#pragma clang diagnostic pop
                    });
            }
    }
    @catch (NSException *exception) {
        NSLog(@"ERROR: %@", [exception description]);
    }
    @finally {
        compblock(YES);
    }
}

The code is particularly slow while running a packages (always more than 30)..

Any Ideas on how solve?

Upvotes: 0

Views: 150

Answers (1)

dimitrirostavo
dimitrirostavo

Reputation: 326

I am not sure if this will help but Apple's installer binary at /usr/sbin/installer does not install more than one package at a time. So even though you have everything dispatched on a queue the underlying tool that gets invoked serializes it and installs one package at time.

So if you have 30 packages (or .pkgs) the installer tool will spend a lot of time unarchiving it and installing it.

I don't think you can get around it without writing your own version of the "installer" tool that does what you want.

Upvotes: 1

Related Questions