2012-01-14 26 views
14

Bir Kakao uygulamasından bir Python komut dosyasını çalıştırmaya çalışıyorum. Ana iş parçacığı üzerinde gayet iyi çalışıyor, ancak arka planda, eşzamanlı bir GCD kuyruğunda çalışmasını isterim. Paylaşılan bir tekil örneğini kullanarak, aşağıdaki örnek yöntemi çağrılabilir (defalarca) script Bundan sonraKODA komut dosyasından çalışan Python komut dosyasını GCD kullanarak yönetme

- (BOOL)setupPythonEnvironment { 
    if (Py_IsInitialized()) return YES; 

    Py_SetProgramName("/usr/bin/python"); 
    Py_Initialize(); 

    NSString *scriptPath = [[NSBundle mainBundle] pathForResource:@"MyScript"  ofType:@"py"]; 

    FILE *mainFile = fopen([scriptPath UTF8String], "r"); 
    return (PyRun_SimpleFile(mainFile, (char *)[[scriptPath lastPathComponent] UTF8String]) == 0); 
} 

: Ben kurulum için Python komut dosyasını çalışan bir yönetici sınıfını aşağıdaki yöntemi kullanıyorum

yöneticisi sınıfı:

from Foundation import * 

def run_with_arguments(arguments): 
# ...a long-running script 

class MyScriptExecutor(NSObject): 
    @classmethod 
    def runWithArguments_(self, arguments): 
     return run_with_arguments(arguments) 
: aşağıdaki Python koduna

- (id)runScriptWithArguments:(NSArray *)arguments { 
    return [NSClassFromString(@"MyScriptExecutor") runWithArguments:arguments]; 
} 

yukarıdaki amacı-C kodu kanca

Bu, her zaman yukarıdaki Objective-C yöntemlerini ana sıradan çalıştırdığımda çalışır, ancak betik başka bir sıradan çalıştırıldığında null değerini döndürür. Birisi bana yapmaya çalıştığım şeyi desteklemiyorsa ve etrafta iyi bir yol olup olmadığını bana açıklayabilir mi?

Python komut dosyalarına sıkça denir ve uzun süre çalışır, bu nedenle ana iş parçacığı üzerinde çok yavaş olur, bir seri sıra çalıştırır. Ayrıca, Objective-C içinde eşzamanlılık kodunu olabildiğince içermek istiyorum. piton gömme özgü bazı bazı oldukça karmaşık parçacığı endişeler vardır gibi

sayesinde this page itibaren

+0

Bu örnekte yaptığınız şeyi gerçekten bilmek için yeterli bilgi yok. – jkh

+1

Python binary'ini xcode ile nasıl entegre ettiğinizi söyler misiniz? – bijan

cevap

11

görünüyor. Bu senaryoları ayrı bir işlemde çalıştırmanın bir sebebi var mı? Örneğin, aşağıdaki -runBunchOfScripts yöntemi, betiğin paralel arka plan kuyruğunda on kez (-runPythonScript'u çağırarak) çalıştırarak sonuçta elde edilen çıktıları bir dizi diziye toplar ve ardından tüm komut dosyaları tamamlandıktan sonra nesneyi ana iş parçacığına geri çağırır. :

- (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..."); 
} 

Doğal ayrı süreçleri kullanarak yaklaşımı vardır bunu başlatabilir süreç sayısının sabit bir sınırı olmak, ancak çok daha az dolu tehlike ile bütününü gömme daha görünüyor değil en az biri sınırlamaları, var çevirmen. Komut dosyaları ile barındırma ortamı arasında sohbet etmek zorunda kalmazsanız, bunun daha iyi bir yaklaşım olacağını söyleyebilirim.

+0

Teşekkürler, @ipmcc. Ne yazık ki, komut dosyaları birkaç kez çalıştırmak zorunda kalacak. Çok kısa sürede bu zor sınırlamaya varacak kadar yeter. Bu yüzden Python ortamını bir kez kurmayı umuyordum. Aslında, betik Python yürütücüsüne NSString olarak "eval" in "güvenli" bir sürümü kullanılarak değerlendirilmek üzere gönderilir. –

+3

NSTask ile benzer bir çözüm yapabilirsiniz; Bir (veya n) uzun süredir çalışan Python yorumlayıcı görevini başlatın ve stdin ve 'eval' komut dosyalarının okunmasını sağlayın ve çıktıyı standart çıktıdan toplayabilirsiniz. Komut dosyalarınızla yalnızca dizeleri kullanarak etkileşime girebilirseniz, bu, tercümanın (en azından oturduğum yerden) gömülmesinden daha mantıklı olacaktır. – ipmcc

+0

Brilliant. Bu kesinlikle yapmalı! –

İlgili konular