Reputation: 6433
I am running a mathematical formula in a NSOperation
:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:20];
for (int i = 0; i<runCount; i++) {
NSInvocationOperation *op =[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(runFormula:) object:frm];
[queue addOperation:op];
}
Here is the method body:
-(void)runFormula:(NSDictionary *)frm
{
NSMutableString *formula = [[frm objectForKey:kFormulaExpresion] mutableCopy];
NSArray *variables = [frm objectForKey:kVariableArray];
evals = [self evaluateVariables:variables];
for (NSDictionary *var in evals) {
NSString *sym = [var objectForKey:kVariableSymbol];
[formula replaceOccurrencesOfString:sym withString:[[var objectForKey:@"numVal"] stringValue] options:NSCaseInsensitiveSearch range:NSMakeRange(0, [formula length])];
}
//parse formula
double result = [formula evaluateMath];
NSLog(@"formula %@ the result : %f",formula,result);
NSNumber *resNo = [NSNumber numberWithDouble:result];
[self performSelectorOnMainThread:@selector(addNewResult:) withObject:resNo waitUntilDone:NO];
}
The problem is that if I give a runCount of 100 I only receive approximately 96 results... Why is that? One more thing: the first result is nonsense, but the other 94-95 are ok.
This is the data aggregation method...
#pragma mark -- data aggregation delegate
-(void)addNewResult:(NSNumber *)nr
{
NSLog(@"index : %i result: %f",currentIndex,[nr doubleValue]);
[[self delegate] didReceiveResult:nr];
resultsArray[currentIndex]=[nr doubleValue];
currentIndex ++;
if ( (currentIndex % percentVal) == 0) {
[[self delegate] percentCompleted];
}
}
Could the problem be that this is in the same class as the concurrent methods?
Upvotes: 2
Views: 106
Reputation: 437472
Two thoughts:
You haven't shown us enough for us to diagnose this, but you have potentially 20 concurrent operations iterating through your evals
instance variable, which they all update. That can't be good. I might suggest a local variable for the result of [self evaluateVariables:variables]
that you can iterate through. See my sample below.
When you say that only 96 are running, are absolutely sure of that? Is it possible that they're just not finishing in the order that you added them to the queue?
So, I might suggest:
-(void)runFormula:(NSDictionary *)frm
{
NSMutableString *formula = [[frm objectForKey:kFormulaExpresion] mutableCopy];
NSArray *variables = [frm objectForKey:kVariableArray];
NSArray *evals = [self evaluateVariables:variables]; // LOCAL VAR
for (NSDictionary *var in evals) {
NSString *sym = [var objectForKey:kVariableSymbol];
[formula replaceOccurrencesOfString:sym withString:[[var objectForKey:@"numVal"] stringValue] options:NSCaseInsensitiveSearch range:NSMakeRange(0, [formula length])];
}
//parse formula
double result = [formula evaluateMath];
NSLog(@"formula %@ the result : %f",formula,result);
NSNumber *resNo = [NSNumber numberWithDouble:result];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self addNewResult:resNo];
}];
}
Note, in the above code block, just as a matter of style, if I'm using operations, I stay within the NSOperationQueue
metaphor when dispatching back to the main queue. It doesn't matter, I don't think, but it feels a little more consistent.
Likewise, in the initial invocation, you can always contemplate the block variation if it makes it more readable. You can also log i
if you want to see the diagnostic information that identifies the individual operations so you can assure yourself that they're all being run:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:20];
for (int i = 0; i < runCount; i++) {
[queue addOperationWithBlock:^{
NSLog("started %d", i); // log i if you want to see that diagnostic information, too
[self runFormula:frm];
NSLog("finished %d", i);
}];
}
Upvotes: 0