2011-07-14 31 views
1

我正在循環由核心數據謂詞檢索的文件路徑數組,每循環迭代一次壓縮和上傳每個文件,總共大約有4或5000個文件。 (我用於壓縮的技術基本上是這裏描述的技術:Best way to loop through a lot of files and zip each one separately?)目前,我在Xcode的調試模式下運行應用程序。經過一段時間,隨着循環的每次迭代,不僅應用程序運行速度會變慢,Xcode也會 - 實際上,我的整個計算機的響應速度都會降低。我正在研究有關NSStrings,NSArrays,NSNotifications等高效循環的一般規則,但我也希望有人能夠指出我的代碼中存在明顯的瓶頸和低效率。雖然我的代碼使用垃圾收集,但我試圖用可能會有所作爲的小希望來發布調用,儘管我的理解是它不應該這樣做。下面是我的代碼的精簡版只重要的部分:如何優化用於壓縮和上傳文件的循環

//Zip paths saved in Core Data and upload them to a server 
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 

//get path of the shell script that zips a file 
NSString *zipShellScript = [[NSBundle mainBundle] pathForResource:@"backupzipper" 
                  ofType:@"sh"]; 

//get array of File managed objects related to User managed object 
NSArray *filesToUpload = [User files]; 

//args for the shell script 
//NSString *sourceFilePath = [NSString string]; 
//NSString *targetFilename = [NSString string]; 
//NSString *targetFilePath = [NSString string]; 

//the following appears to make a big improvement 
NSString *sourceFilePath = [[NSString alloc] initWithString:[NSString string]]; 
NSString *targetFileName = [[NSString alloc] initWithString:[NSString string]]; 
NSString *targetFilePath = [[NSString alloc] initWithString:[NSString string]]; 

NSError *error; 

for (File *file in filesToUpload) //loop through array of File managed objects 
{ 
    NSTask *task = [[NSTask alloc] init]; 

    sourceFilePath = file.path; 
    targetFilename = [NSString stringWithFormat:@"%@.zip", 
         [[sourceFilePath lastPathComponent] 
         stringByDeletingPathExtension]]; //e.g. misc.doc will produce misc.zip 

    [task setArguemnts:[NSArray arrayWithObjects:zipShellScript, 
         sourceFilePath, //full path of file to zip e.g. /Users/stifin/documents/misc.doc 
         workingDirectory, //where the zip will be placed e.g. /Users/stifin/Library/Application Support/MyApp/ 
         targetFilename, //filename after zipping e.g. misc.zip 
         nil]]; 
    [sourceFilePath release]; //my attempt to reduce memory usage even though this is garbage collected app 
    [targetFilename release]; 

    [task [email protected]"/bin/sh"]; 
    [task setStandardInput:[NSPipe pipe]]; //fixes odd behaviour where NSLog no longer works after NSTask 

    //do zip 
    [task launch]; 
    [task waitUntilExit]; 

    if ([task terminationReason] == NSTaskTerminationReasonExit) 
    { 
     [task release]; //doubt this helps 

     [self uploadFile:targetFilePath]; //method just sleeps for 1 sec to simulate upload time 

     file.dateUploaded = [NSDate date]; 
     error = nil; 
     if ([context save:&error]) 
      NSLog(@"Saved ok"); 
     else 
      NSLog(@"Save error: %@", [error localizedDescription]); 

     //delete zip from working directory 
     [self cleanUpFile:targetFilePath]; 
     [targetFilePath release]; //doubt this helps 

     //send notification of file processed 
     info = [NSDictionary dictionaryWithObjectsAndKeys: 
       file.filename, @"name", 
       file.sizeBytes, @"size", 
       [NSNumber numberWithBool:YES], @"success", 
       nil]; 
     [nc postnNotificationName:@"FileProcessed" object:nil userInfo:info]; 
     [info release]; //doubt this helps 
    } 
    else { 
     //handle task failure 
    } 
} 
[nc removeObserver:self]; 
+0

我發現這個建議[「避免autorelease」](http://www.mulle-kybernetik.com/artikel/Optimization/opti-5.html)。我沒有想到應用於GC環境,但我相應地改變了shell腳本的參數(在上面編輯的代碼中),並且對於顯着的改進感到驚訝。 – stifin

+0

只要你明白它在做什麼,autorelease沒什麼問題。我會說「避免在緊密循環中使用自動釋放或使用自己的本地池,每隔一段時間排空它」會更重要。 –

回答

1

正如documentation指出,-release被忽略。如果要立即收集,請使用[[NSGarbageCollector defaultCollector] collectIfNeeded];或甚至-collectExhaustively。不要每循環一趟,每一百次左右。

當然,所有這一切都假定您已經使用了Instruments來確保這是問題所在。你沒有說過你是否這樣做過,這導致我相信你正在做出假設。這個問題可能只是在其他地方(儘管我同意這是迄今爲止最可能的候選人 - GC +在緊密循環中的許多分配需要一些額外的照顧)。不是一個好的工作方式。先測量,然後優化。

+0

非常感謝!你是對的:我還沒有使用過儀器。我是Mac編程新手,所以還沒有找到使用什麼工具來做到這一點。我實際上並沒有假設什麼放慢了代碼,併爲此發佈了我的代碼。我的[字符串發佈]聲明並不是因爲我認爲他們明確是​​罪魁禍首 - 我完全期望有人指向完全可以在我的代碼中看到的其他內容。但是,我知道瓶頸是與這個循環相關的,因爲在執行到達這個循環時,一切都會變慢。將調查儀器。 Thx – stifin

+0

我有理由相信你的直覺是正確的,因爲這種情況肯定會導致GC資源佔用(GC不被允許運行收集),但是你可能會對其他的事情感到驚訝。儀器具有特定於GC的工具。使用這些以及Time Profiler工具。 –

+0

您可以使用一些您通常會作爲最佳實踐來做的事情來編輯我的代碼,以便我可以瞭解這些概念的實際外觀嗎?我並不是要求你假設瓶頸在哪裏 - 只是優化已經應用良好實踐的代碼比編寫不好的代碼更容易,然後嘗試優化它。 – stifin

0

如果你真的想加快速度,每個CPU內核創建1個線程,並將列表分開。在任何現代CPU上,這都會將壓縮速度提高4-8倍!

如果您的文件很小,它也會增加很多上傳速度,因爲很多時間都用於管理連接而不是實際發送數據。

對於較大的文件(超過幾百Kb)甚至1個CPU核心,至少有兩個上傳同時進行會很有用,因爲有些服務器會限制每個連接帶寬,並且允許使用完整上傳帶寬(總是在上傳,而不是等待壓縮或連接完成)。