Running Python script from Cocoa application using GCD

前端 未结 1 1737
醉酒成梦
醉酒成梦 2021-01-31 11:16

I\'m trying to run a Python script from a Cocoa app. It\'s working just fine on the main thread, but I\'d like to have it running in the background, on a concurrent GCD queue.

1条回答
  •  无人及你
    2021-01-31 11:47

    From this page, it looks like there are some some pretty complex threading concerns specific to embedding python. Is there a reason you couldn't just run these scripts in a separate process? For instance, the following -runBunchOfScripts method would run the script ten times (by calling -runPythonScript) on a parallel background queue, collecting the resulting outputs into an array of strings, and then calling your object back on the main thread once all the scripts has completed:

    - (NSString*)runPythonScript
    {
        NSTask* task = [[[NSTask alloc] init] autorelease];
        task.launchPath = @"/usr/bin/python";  
        NSString *scriptPath = [[NSBundle mainBundle] pathForResource:@"MyScript" ofType:@"py"];
        task.arguments = [NSArray arrayWithObjects: scriptPath, nil];
    
        // NSLog breaks if we don't do this...
        [task setStandardInput: [NSPipe pipe]];
    
        NSPipe *stdOutPipe = nil;
        stdOutPipe = [NSPipe pipe];
        [task setStandardOutput:stdOutPipe];
    
        NSPipe* stdErrPipe = nil;
        stdErrPipe = [NSPipe pipe];
        [task setStandardError: stdErrPipe];
    
        [task launch];        
    
        NSData* data = [[stdOutPipe fileHandleForReading] readDataToEndOfFile];
    
        [task waitUntilExit];
    
        NSInteger exitCode = task.terminationStatus;
    
        if (exitCode != 0)
        {
            NSLog(@"Error!");
            return nil;
        }
    
        return [[[NSString alloc] initWithBytes: data.bytes length:data.length encoding: NSUTF8StringEncoding] autorelease];
    }
    
    - (void)runBunchOfScripts
    {
        dispatch_group_t group = dispatch_group_create();
        NSMutableArray* results = [[NSMutableArray alloc] init];
        for (NSUInteger i = 0; i < 10; i++)
        {
            dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                NSString* result = [self runPythonScript];
                @synchronized(results)
                {
                    [results addObject: result];
                }
            });
        }
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            [self scriptsDidFinishWithResults: results];
            dispatch_release(group);
            [results release];
        });
    }
    
    - (void)scriptsDidFinishWithResults: (NSArray*)results
    {
        NSLog(@"Do something with the results...");
    }
    

    Naturally the approach of using separate processes has it's limitations, not the least of which being the hard limit on the number of processes you can launch, but it seems a lot less fraught with peril than embedding the entire interpreter. I would say that unless you need to interact chattily between the scripts and the hosting environment, this would be a better approach.

    0 讨论(0)
提交回复
热议问题