我目前有一个shell脚本,在GraphicsMagick的帮助下,一个接一个地处理许多图像。它运行良好,所有的计算都是正确的,一切正常。(这不是一个"简单"的脚本,它涉及到从JSON文件读取尺寸,根据许多约束转换一堆图像)。
当我们使用双核或四核计算机时,我想并行化它。作为一个iPhone开发者,我喜欢向Mac开发介绍自己,我想用XCode和Objective-C使用"命令行工具"模板创建它。
到目前为止一切顺利,但是现在我要面对"任务分派器"对象的设计。在运行循环中运行NSTasks,在单独的线程中,使用块,带或不带GCD,带或不带ARC之间,我相当迷失。
如何做到这一点?我正在考虑使用简单的线程来生成NSTasks,让它们在完成时报告,并通知我的调度程序的委托,以便它可以升级其进度条。但我真的很想联系中央调度中心。有没有人有什么想法,想法,建议,什么该做什么不该做?
编辑:我正在阅读苹果的文档,并找到了NSOperationQueue类。有没有可能这个正是我在这里需要的 ?用于启动包括参数和环境变量在内的独立进程的一个好类是NSTask。有关详细信息,请参阅文档。下面是一个小命令行工具,它启动10个并发进程并等待它们完成。NSOperationQueue在这里是多余的,因为任务已经并发地启动了。
——编辑:改进版本限制并发——
int main (int argc, const char * argv[])
{
@autoreleasepool {
// Let's not have more than 5 parallel processes
dispatch_semaphore_t limit = dispatch_semaphore_create(5);
dispatch_semaphore_t done = dispatch_semaphore_create(0);
for (int i=0; i<10; i++) {
// Setup the taks as you see fit including the environment variables.
// See docs on NSTask for more on how to use this object.
NSTask *task = [[NSTask alloc] init];
task.launchPath = @"/bin/ls";
task.arguments = [NSArray arrayWithObject:@"-la"];
task.terminationHandler = ^(NSTask *task) {
dispatch_semaphore_signal(limit);
if (i==9) dispatch_semaphore_signal(done);
};
dispatch_semaphore_wait(limit, DISPATCH_TIME_FOREVER);
[task launch];
}
dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
dispatch_release(limit);
dispatch_release(done);
}
return 0;
}
—原版本—
int main (int argc, const char * argv[])
{
@autoreleasepool {
NSObject *lock = [[NSObject alloc] init];
int __block counter = 10;
for (int i=0; i<10; i++) {
// Setup the taks as you see fit including the environment variables.
// See docs on NSTask for more on how to use this object.
NSTask *task = [[NSTask alloc] init];
task.launchPath = @"/bin/ls";
task.arguments = [NSArray arrayWithObject:@"-la"];
task.terminationHandler = ^(NSTask *task) {
@synchronized(lock) { counter--; }
};
[task launch];
}
while (counter)
usleep(50);
[lock release];
}
return 0;
}
在您的情况下,您可能希望将NSTask对象保存在一个数组中,以便于管理。
yes - NSOperation
/NSOperationQueue
适合此任务
我会这样开头:
@protocol MONTaskRequestDelegate
- (void)taskRequestDidComplete:(MONTaskRequest *)taskRequest;
@end
@interface MONTaskRequest : NSOperation
{
@private
NSTask * task;
NSObject<MONTaskRequestDelegate>* delegate; /* strong reference. cleared on cancellation and completion, */
}
- (id)initWithTask:(NSTask *)task delegate:(NSObject<MONTaskRequestDelegate>*)delegate;
// interface to access the data from the task you are interested in, whether the task completed, etc.
@end
@implementation MONTaskRequest
// ...
- (void)performDelegateCallback
{
[self.delegate taskRequestDidComplete:self];
self.delegate = nil;
}
- (void)main
{
NSAutoreleasePool * pool = [NSAutoreleasePool new];
[self runTheTask];
// grab what is needed and handle errors
[self performDelegateCallback];
[pool release];
}
- (void)cancel
{
[super cancel];
[self stopTaskIfPossible];
[self performDelegateCallback];
}
@end
那么你可以使用NSOperationQueue
来限制活动任务的数量到一个合理的数量
我为此目的使用[myObj performSelectorInBackground:@selector(doSomething) withthobject:nil];NSObject的功能
这个想法很简单:你写一个方法来完成这项工作,使用前面提到的方法从主线程调用它,然后调用一些回调选择器,如果你需要以某种方式处理来自不同线程的结果。