System resources and number of operations on an NSOperationQueue
System resources and number of operations on an NSOperationQueue
- Subject: System resources and number of operations on an NSOperationQueue
- From: Antonio Nunes <email@hidden>
- Date: Sun, 14 Nov 2010 09:58:48 +0000
I'm developing a daemon to run tasks as files get dropped into a folder. When a new file is detected, a new operation gets put onto the daemon's operation queue. The operation launches a task and waits for it to finish, then the operation exits.
The issue I am seeing is that the operation queue appears to indiscriminately run operations as they are added to the queue, regardless of system resources, thus bringing the whole system to a crawl. I thought, from reading the documentation, that the queue would be intelligent about how many operations it would have running at the same time, depending on system resources such as number of cores and available memory. Since this doesn't seem to be the case, I have to assume something is not quite right with my implementation.
My question: how can I ensure that no more operations are launched at any one time than the system can handle? Also, is there a way to find out the number of cores on a machine so that I can set that as a hard limit of number of operations on an NSOperationQueue?
The code is meant for 10.6.0 or higher and runs with garbage collection on.
Here is an outline of how my code implements the daemon and the operations:
All the daemon itself does, really, is to fire up a single directory watcher, which is where all the action takes place. It then waits until it is signaled for termination, at which point it tears down the directory watcher and exits.
The crucial part of main() in the daemon:
----------
directoryWatcher = [[ANDirectoryWatcher alloc] initWithOptionsBlaBlaBla...];
[directoryWatcher start];
while (1) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
}
// Should never get here
[directoryWatcher stop];
----------
The directory watcher owns a single operation queue, to which it adds operations as new files arrive in the folder it watches:
----------
-(void) handleNewFileFoundNotification:(NSNotification *)notification
{
NSString *sourcePath = [[notification userInfo] objectForKey:@"path"];
NSFileManager *localFileManager=[[NSFileManager alloc] init];
NSDirectoryEnumerator *dirEnum = [localFileManager enumeratorAtPath:sourcePath];
NSString *file;
while (file = [dirEnum nextObject]) {
if ([[file pathExtension] isEqualToString: @"ext"]) {
NSString *filePath = [sourcePath stringByAppendingPathComponent:file];
// Process the document only if the path is new. Otherwise the document is already being processed.
if ( ! [self previouslyKnownPath:filePath] ) {
ANTaskLauncherOperation *operation = [[ANTaskLauncherOperation alloc] initWithSourceFileURL:[NSURL fileURLWithPath:filePath]
...other options...];
[self.operationInfo setValue:operation forKey:filePath];
[self.operationQueue addOperation:(NSOperation *)operation];
}
}
}
}
----------
The task launcher operation contains only three methods:
- An init method that is passed the required info and sets up essential instance variables based on the arguments.
- The following two methods:
----------
- (void)completeOperation
{
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
self.executing = NO;
self.finished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
-(void)main
{
fprintf(stdout, "%s Received file: \"%s\"\n", ANTaskLauncherCurrentTimeString(), self.sourceFileURL.path.lastPathComponent.UTF8String);
fflush(stdout);
NSTask *task = [[NSTask alloc] init];
NSMutableArray *args = [NSMutableArray array];
// Find path to binary
Dl_info info;
int errDlAddr = dladdr( (const void *)__func__, &info );
if(errDlAddr == 0) {
return;
}
char *exec_path = (char *)(info.dli_fname);
NSString *executablePath = [NSString stringWithCString:exec_path encoding:NSUTF8StringEncoding];
executablePath = [executablePath substringToIndex:executablePath.length - 1];
NSString *sourceFileName = self.sourceFileURL.lastPathComponent;
NSString *outputPath = [self.outputURL.path stringByAppendingPathComponent:sourceFileName];
...snip, adjusting outputPath some more...
/* set arguments */
[args addObject:@"-f"];
[args addObject:self.sourceFileURL.path];
...snip more arguments...
[task setLaunchPath:executablePath];
[task setArguments:args];
...snip, making sure file has arrived completely before we continue...
[task launch];
[task waitUntilExit];
[[NSNotificationCenter defaultCenter] postNotificationName:ANOperationCompletedNotification
object:self];
[self completeOperation];
}
----------
The ANOperationCompletedNotification is caught by the directory watcher, which performs some internal cleanup.
Any pointers as to why the operation queue doesn't appear to manage the spawning of operations according to available system resource appreciated.
- António
-----------------------------------------------------------
What you have inside you expresses itself through both your
choice of words and the level of energy you assign to them.
The more healed, whole and connected you feel inside,
the more healing your words will be.
--Rita Goswami
-----------------------------------------------------------
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden