如何优化拉链和上传文件的循环

时间:2011-07-14 13:31:58

标签: objective-c cocoa macos optimization

我循环遍历由核心数据谓词检索的文件路径数组,每次迭代循环时压缩和上传每个文件,总共约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 setLaunchPath@"/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];

2 个答案:

答案 0 :(得分:1)

documentation所述,-release被忽略。如果您想立即收集,请使用[[NSGarbageCollector defaultCollector] collectIfNeeded];或甚至-collectExhaustively。不要每次通过循环,每隔一百左右就这样做。

当然,所有这些都假设您已经使用过仪器来确保这是问题所在。你还没有说过你是否已经这样做了,这让我相信你在做出假设。问题可能只是在其他地方(虽然我同意这是迄今为止最有可能的候选人 - GC +在紧密循环中的许多分配需要一些额外的关注)。工作不是一个好方法。先测量,然后优化。

答案 1 :(得分:0)

如果你真的想加快速度,可以为每个CPU内核创建1个线程并将列表分开。在任何现代CPU上,这将使拉链速度提高4-8倍!

如果您的文件很小,它也会大大提高上传速度,因为花费大量时间来管理连接而不是实际发送数据。

对于较大的文件(超过几百Kb)或甚至1个CPU核心,由于某些服务器限制每个连接带宽,因此至少同时进行2次上传仍然很有用,并且它将允许使用完整的上载带宽(总是上传而不是等待压缩或连接完成)。