Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c Obj-C设计模式:并行任务启动器_Objective C_Multithreading_Parallel Processing_Grand Central Dispatch_Nstask - Fatal编程技术网

Objective c Obj-C设计模式:并行任务启动器

Objective c Obj-C设计模式:并行任务启动器,objective-c,multithreading,parallel-processing,grand-central-dispatch,nstask,Objective C,Multithreading,Parallel Processing,Grand Central Dispatch,Nstask,我目前有一个shell脚本,它在GraphicsMagick的帮助下一个接一个地处理许多图像。工作正常,所有计算都正确,一切正常。(这不是一个“简单”的脚本,它涉及从JSON文件中读取维度,转换一组与许多约束相关的图像) 当我们使用双核或四核计算机时,我想将其并行化。作为一名iPhone开发人员,我想介绍一下Mac开发,我想用XCode和Objective-C使用“命令行工具”模板创建它 到目前为止还不错,但现在我要面对“任务调度器”对象的设计。在运行循环中运行NSTASK、在单独的线程中运行N

我目前有一个shell脚本,它在GraphicsMagick的帮助下一个接一个地处理许多图像。工作正常,所有计算都正确,一切正常。(这不是一个“简单”的脚本,它涉及从JSON文件中读取维度,转换一组与许多约束相关的图像)

当我们使用双核或四核计算机时,我想将其并行化。作为一名iPhone开发人员,我想介绍一下Mac开发,我想用XCode和Objective-C使用“命令行工具”模板创建它

到目前为止还不错,但现在我要面对“任务调度器”对象的设计。在运行循环中运行NSTASK、在单独的线程中运行NSTASK、使用块、使用或不使用GCD、使用或不使用ARC时,我完全迷失了方向

如何做到这一点?我在考虑使用简单线程生成NSTask,让它们在完成时报告,并通知我的调度程序的委托,以便它可以升级其进度条。但我真的很想和中央调度联系。有人对做什么和不做什么有什么想法、想法和建议吗


编辑:我正在阅读苹果的文档,找到了NSOperationQueue类。这可能正是我在这里需要的吗?

为此,我使用[myObj performSelectorInBackground:@selector(doSomething)with object:nil];NSObject的功能


想法很简单:编写一个方法来完成这项工作,使用前面提到的方法从主线程调用它,然后如果需要以某种方式处理来自不同线程的结果,则调用一些回调选择器

一个用于启动独立进程(包括参数和环境变量)的好类是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[]
{
@自动释放池{
//让我们不要有超过5个并行进程
调度信号量限制=调度信号量创建(5);
dispatch\u semaphore\u t done=dispatch\u semaphore\u create(0);

对于(int i=0;iyes-
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
@protocol-MONTaskRequestDelegate
-(void)taskRequestDidComplete:(MONTaskRequest*)taskRequest;
@结束
@接口请求:NSOperation
{
@私人的
NSTask*任务;
NSObject*委托;/*强引用。取消和完成时清除*/
}
-(id)initWithTask:(NSTask*)任务委托:(NSObject*)委托;
//接口,用于访问您感兴趣的任务中的数据、任务是否已完成等。
@结束
@执行请求
// ...
-(无效)PerformDeleteCallback
{
[self.delegate taskRequestDidComplete:self];
self.delegate=nil;
}
-(无效)主要
{
NSAutoreleasePool*池=[NSAutoreleasePool新建];
[自运行任务];
//抓住需要的东西并处理错误
[自执行远程回调];
[池释放];
}
-(作废)取消
{
[超级取消];
[自行停止任务(如果可能];
[自执行远程回调];
}
@结束

然后,您可以使用
NSOperationQueue
将活动任务的数量限制在合理的范围内。

我知道这种方法,但希望使用更高级的线程形式,如GCD或NSOperationQueue。无论如何,谢谢。这或多或少是我在此期间完成的。事实上,NSOperationQueue正是我想要的(特别是限制活动任务的数量)。感谢您的确认!这是一个很好的解决方案,但有一个缺点:它会为每个并发任务启动一个线程和一个独立进程,这会增加资源需求。@aLevelOfIndirection独立进程是一个需求。此外,NSOperationQueue确实重用线程——它的实现(10.6+)利用libdispatch(又名GCD)。如果要启动的进程数量有限,这很好,但我真的不需要并行启动500个进程(这是平均值,可以增加到数千个)。对于简单的操作来说很有趣,但在本例中,我需要更细粒度的东西,而NSOperationQueue似乎是这里最好的工作马。哇,信号量…自从我10年前第一次发现win32 API以来,一直在想它们是如何工作的!实际上,阅读它时这看起来很简单。我也会尝试看看这个。然后再一次!IIRC,
dispatch.*
函数是由GCD提供的,对吗?@Cyrille:是的,它们是由GCD提供的。
@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