Sto usando cURL
per scaricare circa 1700+ file - che ammontano a circa ~ 290 MB - nella mia app iOS. Ci vogliono circa 5-7 minuti sulla mia connessione Internet per scaricarli tutti usando cURL
. Ma dal momento che non tutti hanno una connessione internet veloce (soprattutto quando si è in viaggio), ho deciso di consentire il download dei file in background, in modo che l'utente possa fare altre cose in attesa del completamento del download. È qui che viene in NSURLSession
.Perché NSURLSession è più lento di cURL quando si scaricano molti file?
Utilizzando NSURLSession
, ci vogliono circa 20+ minuti sulla mia connessione a Internet per scaricare tutti loro mentre l'applicazione è in primo piano. Non mi interessa che sia lento quando l'app è in background, perché capisco che spetta al sistema operativo pianificare i download. Ma è un problema quando è lento anche quando è in primo piano. È questo il comportamento previsto? È a causa della quantità dei file?
Nel caso in cui non sto usando NSURLSession
correttamente, ecco un frammento di come lo sto usando:
// Initialization
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"<my-identifier>"];
sessionConfiguration.HTTPMaximumConnectionsPerHost = 40;
backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegateQueue:nil];
// ...
// Creating the tasks and starting the download
for (int i = 0; i < 20 && queuedRequests.count > 0; i++) {
NSDictionary *requestInfo = [queuedRequests lastObject];
NSURLSessionDownloadTask *downloadTask = [backgroundSession downloadTaskWithURL:[NSURL URLWithString:requestInfo[@"url"]]];
ongoingRequests[@(downloadTask.taskIdentifier)] = requestInfo;
[downloadTask resume];
[queuedRequests removeLastObject];
NSLog(@"Begin download file %d/%d: %@", allRequests.count - queuedRequests.count, allRequests.count, requestInfo[@"url"]);
}
// ...
// Somewhere in (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
// After each download task is completed, grab a file to download from
// queuedRequests, and create another task
if (queuedRequests.count > 0) {
requestInfo = [queuedRequests lastObject];
NSURLSessionDownloadTask *newDownloadTask = [backgroundSession downloadTaskWithURL:[NSURL URLWithString:requestInfo[@"url"]]];
ongoingRequests[@(newDownloadTask.taskIdentifier)] = requestInfo;
[newDownloadTask resume];
[queuedRequests removeLastObject];
NSLog(@"Begin download file %d/%d: %@", allRequests.count - queuedRequests.count, allRequests.count, requestInfo[@"url"]);
}
Ho anche provato ad utilizzare molteplici NSURLSession
, ma è ancora lento. La ragione per cui l'ho provato è che quando utilizzo cURL
, creo più thread (circa 20) e ogni thread scaricherà un singolo file alla volta.
Inoltre, non è possibile ridurre il numero di file bloccandolo, perché ho bisogno che l'app sia in grado di scaricare singoli file poiché li aggiornerò di volta in volta. Fondamentalmente, quando l'app si avvia, controlla se ci sono dei file che sono stati aggiornati e scaricano solo quei file. Poiché i file sono archiviati in S3 e S3 non ha il servizio di zipping, non è possibile comprimerli in un singolo file al volo.
Provare a sostituire 'backgroundSessionConfigurationWithIdentifier:' con 'defaultSessionConfiguration' e confrontare i risultati. Non penso che a iOS importi davvero se la tua app è in esecuzione o meno durante il download su una sessione configurata per download in background. Farà sempre quei download su un processo separato che accelererà la velocità. –
1. Sono d'accordo con Filip: provate temporaneamente ad usare la sessione non in background e penso che potreste vedere la differenza di prestazioni. I miei test aneddotici suggerivano che la sessione in background (anche sparata dal foreground) era più lenta, anche se non l'ho ancora testata di recente. – Rob
2.Quando si utilizza la sessione in background, non è necessario "accodare il primo 20 processo". Basta accodarli tutti. Misurandoli in questo modo, rallenterai il processo in background perché continuerà a riaccendere la tua app se sospesa/terminata. La sessione in primo piano richiede il controllo del grado di concorrenza per evitare timeout, ma non per le sessioni in background. (Poi di nuovo, se stavo controllando il grado di concorrenza in una sessione in primo piano, penso che la coda di operazioni sia la soluzione più semplice in quel caso. Ma forse è accademico se usi la sessione in background.) – Rob