【问题标题】:Unable to sustain a Constant Speed while Uploading files in the background with NSURLSession使用 NSURLSession 在后台上传文件时无法保持恒定速度
【发布时间】:2014-10-08 07:44:21
【问题描述】:

我正在尝试使用 AFURLSessionManager 在后台将大约 100 个图像上传到 S3,就像这里正在做的那样,小批量 10 个 - Manage the number of active tasks in a background NSURLSession

我正在使用共享的 NSURLSession 并在完成某些任务时根据更多任务添加任务。每个文件的平均大小约为 1.6 MB,每个任务队列保证运行的任务数为 5

这是我添加任务的方法: (也可作为更易于阅读的gist

    - (void) addTasksToSessionWithTaskObject:(Task*)taskObject withSessionInitialisationNeeded:(BOOL) needed{

        NSString *filePath = [[NSBundle mainBundle] pathForResource:pathForResourceFile ofType:resourceFileType];
        S3PutObjectRequest *putObjectRequest = [[S3PutObjectRequest alloc] initWithKey:targetFileKey
                                                                              inBucket:_bucketname];
        putObjectRequest.cannedACL = [S3CannedACL publicReadWrite];
        putObjectRequest.filename = filePath;
        putObjectRequest.contentType = [resourceFileType isEqualToString:@"MOV"] ? @"movie/mov" : @"image/jpg";
        putObjectRequest.endpoint = @"http://s3.amazonaws.com";
        putObjectRequest.contentLength=[[[NSFileManager defaultManager]
                                         attributesOfItemAtPath:filePath error:nil] fileSize];
        putObjectRequest.delegate = self;
        [putObjectRequest configureURLRequest];
        NSMutableURLRequest *request = [s3Client signS3Request:putObjectRequest];
        NSMutableURLRequest *request2 = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://s3.amazonaws.com/UploadTest/%@",taskObject.fileKey]]];

        [request2 setHTTPMethod:request.HTTPMethod];
        [request2 setAllHTTPHeaderFields:[request allHTTPHeaderFields]];

        if(needed) {

                sharedSession = [self backgroundSession];   
        }
   NSURLSessionUploadTask *task = [sharedSession uploadTaskWithRequest:request2           fromFile:forFileUrl];

    task.taskDescription = pathForResourceFile;
    [currentlyActiveTaskIdArray addObject:@([task taskIdentifier])];

    [task resume];
}

这就是我对委托所做的事情

- (void)URLSession:(NSURLSession *)sessionI task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error{

    dispatch_async(dispatch_get_main_queue(), ^{

        __block UIBackgroundTaskIdentifier bgTaskI = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
            [[UIApplication sharedApplication] endBackgroundTask:bgTaskI];
        }];

        if([currentlyActiveTaskIdArray containsObject:@([task taskIdentifier])]){
            [currentlyActiveTaskIdArray removeObject:@([task taskIdentifier])];
        }
        if(currentlyActiveTaskIdArray.count < LOWER_SLAB_FOR_TASKS + 1){   
            [self initiateS3UploadForSetOfTasksIsItBeginningOfUpload:NO];
        }
        [[UIApplication sharedApplication] endBackgroundTask:bgTaskI];
    }); 
}

这是添加更多任务的代码

 - (void) initiateS3UploadForSetOfTasksIsItBeginningOfUpload:(BOOL)beginning{
        int i=0;
        for(Task *eachTaskObject in tasksArray){
            if(i < numberOfTasksTobeAdded){  
                [self addTasksToSessionWithTaskObject:eachTaskObject WithSessionInitialisationNeeded:NO];
                i++;
            }
        }
    }

我一直在前台模式和后台模式下运行 100 个文件的测试。在Foreground模式下,文件以一致、稳定、恒定的速度上传,前3分钟完成90个文件,其余10个文件在20秒内完成。

当我在后台模式下运行应用程序时,我希望它上传前 90 个文件的速度与在 3 分钟的前台窗口中一样快,然后放慢速度……但事实并非如此。在后台模式下,它会在第一分钟上传 15 个文件,然后开始减速……很多。它以越来越慢的间隔开始上传 8 个文件批次:1 分钟、3 分钟、5 分钟、10 分钟,现在是 17 分钟。我们在 46 分钟内有 65 个文件。

有没有办法让它保持快速至少 3 分钟,或者在后台保持一致的速度?

更新: 在 Clay 的 cmets 之后,我从 AFURLSessionManager 切换回 NSURLSession,因为正如他所指出的,使用基于块的回调对于 NSURLSession 来说是一项极具风险的业务。此外,我还使用了 HTTPMaximumConnectionsPerHost 并将其设置为 10 左右——这给出了更好的结果,但与我想要的结果相去甚远。

【问题讨论】:

  • 没有太多的时间来查看你的代码,但有几件事需要检查: 1) 你是否在你的 NSURLSessionConfiguration 中设置了 HTTPMaximumConnectionsPerHost?使用它来设置任务队列的“宽度”。 2) 您是否使用 uploadTaskWithRequest 将所有这些请求/任务添加到同一个 NSURLSession?
  • 1) 我已将 HTTPMaximumConnectionsPerHost 设置为 1。我拥有的任务队列一次运行 5 到 9 个任务。那么是否希望我将其设置为围绕这些值? 2)我正在使用单个共享的 AFURLSessionmanager 实例来添加任务..
  • 我把你的代码写成一个要点,这样更容易阅读,在这里:gist.github.com/claybridges/8ca22217830e0ce1a0f1

标签: ios amazon-s3 afnetworking nsurlsession nsurlsessionuploadtask


【解决方案1】:

据我所知,setTaskDidCompleteBlock: 不是 Apple API,NSURLSession 相关方法。它一个AFURLSessionManager 方法(docs)。如果您在这方面使用 AFNetworking,那么您需要宣布 粗体、顶部、前面和中心。这与使用NSURLSession 完全不一样。我猜 AFNetworking 的背景基于NSURLSession 的实现有它自己的弱点和特质。

就我而言,无论我在NSURLSession 上传的持续背景下取得的任何成功都只使用股票 API。


回答问题等

  • 关于 AFNetworking:我们将它用于一般的 web api I/O。在 NSURLSession 出来的时候,AFNetworking 确实没有强大的支持 app-in-background 操作,所以我没有使用它。也许是因为我经历了背景NSURLSessionpain & hazing,我在“现在你有两个问题”的标题下对 AFNetworking 的背景表示怀疑。但也许他们现在已经破解了坚果。

    • 我争取一个NSURLSession。我开始对会话的创建和销毁很随意,但发现这会导致一些真正棘手的问题。这方面的经验似乎各不相同。

    • 我使用默认的HTTPMaximumConnectionsPerHost,没有问题。 Apple 文档对默认值保持沉默,但这是 lldb 在我选择的随机特定设备/操作系统中告诉我的内容:
      (lldb) p [config HTTPMaximumConnectionsPerHost] (NSInteger) $0 = 4
      如果您在后台运行速度变慢时遇到问题,我怀疑调整它是否在正确的轨道上。

    • FWIW,后台NSURLSessions 不支持块接口,仅限委托。

【讨论】:

  • 好点的粘土。我已经转移到 AFURLSessionManager 因为它可以考虑允许无效 SSL 证书的安全策略 - 这是为了解决我遇到的 SSL 错误 - 当我切换回 NSURLSession 并尝试实现你所做的 -我很想知道几件事 a)您是否在维护一个会话并在此会话中添加更多任务 2)正如 Dinkman 在上面关于 HTTPMaximumConnectionsPerHost 的评论中指出的那样,鉴于我拥有的任务队列,我应该设置什么值,运行 5 到 9 个任务。
  • 我看过您的帖子,您可以在真实背景模式下上传 1000 个文件。我只是想知道。您的这个应用程序需要多长时间才能上传 1000 张图片(例如每张 1 MB)。现在我能做到的最好是在 5 分钟内达到 300~350 MB - 你认为我可以走得更远吗?
  • 这个比率似乎相当稳定。我设置了仪器来测量我的 BG 上传速率,并保持一个窗口化的运行平均值,这样我就可以看到我是否正在设定一个足以满足我的目的的静态速率。此外,我想象 BG 上传与(人)睡眠期间发生的大数据等情况,其中 8 小时的时间范围是可以接受的。
  • 补充一点——显然我发现操作系统更喜欢将 100 个 1 MB 的文件上传到一个相同大小的单个大文件中——在后一种情况下,节流率要高得多。跨度>
  • @Xcoder:您应该在自己创建的 Q/A 中发布这些结果,更彻底地记录在案(您提出问题,然后回答问题)。这对部落来说是有用的信息。
猜你喜欢
  • 1970-01-01
  • 2015-04-04
  • 2014-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-27
相关资源
最近更新 更多