为啥 NSURLSession dataTaskWithURL 比 NSData dataWithContentsOfURL 慢得多?

Posted

技术标签:

【中文标题】为啥 NSURLSession dataTaskWithURL 比 NSData dataWithContentsOfURL 慢得多?【英文标题】:Why is NSURLSession dataTaskWithURL significantly slower vs NSData dataWithContentsOfURL?为什么 NSURLSession dataTaskWithURL 比 NSData dataWithContentsOfURL 慢得多? 【发布时间】:2015-05-12 02:49:46 【问题描述】:

我正在尝试从我的服务器下载一个 94KB 的图像文件。我尝试了两种方法:使用NSURLSession dataTaskWithURLNSData dataWithContentsOfURL

NSURLSession:

Globals *global = [Globals getInstance];

// GET request to /mobile/image
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/mobile/image/%@", [global rootUrl], self.photoId]];
NSURLSession * session = [global session];
NSDate *start = [NSDate date];
[[session dataTaskWithURL:url completionHandler:^(NSData *imgData, NSURLResponse *response, NSError *error) 
    NSLog(@"Time taken: %f", [[NSDate date] timeIntervalSinceDate:start]);
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
    if ([httpResponse statusCode] != 200) 
        // error
     else 
        dispatch_async(dispatch_get_main_queue(), ^ 
            UIImage *image = [UIImage imageWithData:imgData];

            CGFloat width = self.photoImageView.frame.size.width;
            CGFloat height = image.size.height / image.size.width * width;
            self.imageHeight.constant = height;

            self.photoImageView.image = image;
        );
    
] resume];

NSData:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ 
    Globals *global = [Globals getInstance];

    // GET request to /mobile/image
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/mobile/image/%@", [global rootUrl], self.photoId]];
    NSDate *start = [NSDate date];
    NSData *imgData = [NSData dataWithContentsOfURL:url];
    NSLog(@"Time taken: %f", [[NSDate date] timeIntervalSinceDate:start]);
    UIImage *image = [UIImage imageWithData:imgData];

    CGFloat width = self.photoImageView.frame.size.width;
    CGFloat height = image.size.height / image.size.width * width;

    dispatch_async(dispatch_get_main_queue(), ^
        self.imageHeight.constant = height;
        self.photoImageView.image = image;
    );
);

这是我的 NSLog 的输出,显示他们完成了多长时间:

NSURLSession:

Time taken: 6.585221
Time taken: 3.619189
Time taken: 4.408179
Time taken: 9.931350
Time taken: 3.689192

NSData:

Time taken: 0.157747
Time taken: 0.135785
Time taken: 0.576947
Time taken: 0.462661
Time taken: 0.337266

下载一个简单的NSData,但我需要稍后使用NSURLSession进行另一个类似的图像下载任务,因为我需要登录会议。

我想知道我是否无意中发现了 NSURLSession 的一个奇怪错误,是否它应该慢得多,因为它具有会话的所有开销,或者我做错了什么。

编辑:

我想通了,谢谢大家的帮助!

我用这个项目的所有连接创建了一个全新的项目,它表现良好。

问题:之前的VC多次调用dataTask。我完全困惑为什么这会影响这个 VC。原来这个类被称为 ViewController(默认名称),而这个 VC 是继承 ViewController 而不是 UIViewController。

因此,从这个 ViewController 的 viewDidLoad 调用 [super viewDidLoad] 实际上是在调用之前的 VC 并重新运行所有这些 dataTask。

如有疑问,请检查会话中的所有其他连接。

【问题讨论】:

用会话的配置(NSURLSessionConfiguration。我将从缓存开始)看看是否有什么对时间有很大影响可能是值得的。 我没有费心去缓存,因为我也没有为 NSData 缓存。 (两者都完全干净。) 至于我的会话配置:NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];NSURLSession *session = [NSURLSession sessionWithConfiguration:config]; 这几乎是默认设置,我没有在其他任何地方更改任何配置。 当我查看 NSURLSession 的网络使用情况时,它似乎在下载任务的中间下降到零 KB/s,然后在几秒钟后返回,重复直到完成。它可能与在后台运行有关吗? 问题不在于上面的代码。问题也不在于NSURLSession,这是一段非常健壮的网络代码。提供的代码不足以重现您描述的问题。或许您可以构造 the simplest possible example 来体现您所描述的问题,并与我们分享? @pchiang 您应该继续发布您的结论作为“答案”,而不是用您的发现编辑问题。见Can I answer my own question? 【参考方案1】:

您遇到了线程问题。 不要在后台线程中运行该代码(NSURLSession 代码)!在主线程上运行它。别担心,这不会阻塞主线程; NSURLSession 的全部意义在于 it 异步操作,因此您不必这样做。

【讨论】:

您的论点是,如果您碰巧在后台线程中使用NSURLSession,您会看到这样的延迟吗?与NSURLConnection 不同,NSURLSession 在您想要运行它的任何线程中都表现得非常好。 @Rob 不,我认为他的线程问题在其他地方;我们不知道的事情正在争论中。我只是想让他离开那个后台线程,因为它们很难处理。 同意,问题出在其他地方,而不是到目前为止问题中提供的代码中。 我想通了,谢谢你的帮助!我创建了一个具有所有连接的全新项目,并且表现良好。问题:之前的VC多次调用dataTask。我完全困惑为什么这会影响这个 VC。原来这个类被称为 ViewController(默认名称),而这个 VC 是继承 ViewController 而不是 UIViewController。因此,从这个 ViewController 的 viewDidLoad 调用 [super viewDidLoad] 实际上是在调用之前的 VC 并重新运行所有这些 dataTask。 这很好,但我认为我不应该为此获得任何“接受”!我们猜测问题出在其他地方,但仅此而已。

以上是关于为啥 NSURLSession dataTaskWithURL 比 NSData dataWithContentsOfURL 慢得多?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 NSURLSession uploadTaskWithRequest:fromData: 无法上传到 php 服务器?

为啥我的 NSURLSessionDownloadTask 下载不会到达我的客户端?

NSURLSession 啥时候运行?

NSURLSession 委托跨类拆分 - NSURLSession、NSURLUploadTask、NSURLDownloadTask

iOS开发系列-NSURLSession

3 AFURLSessionManager