Why is NSURLSession:delegate: significantly slower

2019-06-09 03:02发布

问题:

I noticed that my application is connecting to remote resources way slower than web browsers, or cURL and decided to do some digging.

I've been using NSURLSession sessionWithConfiguration:delegate: to handle server responses, and decided to try instead using NSURLSession dataTaskWithRequest:completionHandler:. The test methods are below:

-(void)connectWithDelegate:(NSString *)url
{
    semaphore = dispatch_semaphore_create(0);
    session = [NSURLSession sessionWithConfiguration: [NSURLSessionConfiguration defaultSessionConfiguration]
                                            delegate: self
                                       delegateQueue: nil];

    NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: url]
                                                       cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
                                                   timeoutInterval: 60.0];


    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest: req];

    [dataTask resume];
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}

- (void)connectWithCompletionHandler:(NSString *)url
{
    semaphore = dispatch_semaphore_create(0);
    session = [NSURLSession sharedSession];
    NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: url]
                                                       cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
                                                   timeoutInterval: 60.0];

    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:req completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error){
        if (!error)
            dispatch_semaphore_signal(semaphore);
    }];

    [dataTask resume];
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}

Running these tests repeatedly with a range of different network conditions, the connectWithCompletionHandler: method consistently outperforms connectWithDelegate:. On slow connections it can be as much as 6 times faster to return.

The full test code can be found here.

Running this test over 20 iterations on a 5Mb/s link with 50 ms latency yields an average connection time of 0.6 seconds for connectWithCompletionHandler: and 2 seconds for connectWithDelegate:

What accounts for the difference in response time between these two methods...?