Je souhaite télécharger en même temps certains fichiers, par exemple 100 fichiers. J'ai donc décidé d'ajouter mes threads de téléchargement à une file d'attente de répartition, et GCD ajustera le nombre de threads qui s'exécuteront en même temps.
Le problème ici est: le bloc dans dispatch_async
sera terminé immédiatement, car task
s'exécutera sur un autre thread. Donc, si la longueur de urls
est 100, cela créera 100 threads immédiatement.
var queueDownloadTask = dispatch_queue_create("downloadQueue", nil)
for url in urls {
dispatch_async(queueDownloadTask) {
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let fileTransferSession = NSURLSession(configuration: config)
let task = fileTransferSession.downloadTaskWithURL(url, completionHandler: { (responseUrl, response, error) -> Void in
println("completed")
})
task.resume()
}
}
Comment puis-je configurer le bloc dans dispatch_async
attendre la fin du téléchargement? Je ne veux pas utiliser dispatch_semaphore
, car il ne permet d'exécuter qu'une seule tâche de téléchargement à la fois.
Pour développer la réponse d'Abhinav, vous devez:
dispatch_group_create()
pour créer un groupe.dispatch_group_enter(group)
avant de démarrer chaque tâche de téléchargement.dispatch_group_leave(group)
à l'intérieur du gestionnaire d'achèvement de la tâche.dispatch_group_notify(group, queue, ^{ ... })
pour mettre en file d'attente un bloc qui sera exécuté lorsque toutes les tâches seront terminées.Vous pouvez voir un exemple dans cet article .
(Au fait, ce n'est pas vrai que faire 100 dispatch_async
s dans une rangée créera 100 threads immédiatement. Le système conserve le contrôle du nombre de threads à utiliser pour satisfaire la file d'attente. Cependant, votre code n'attend aucune des tâches pour se terminer avant de revenir, ni ne tente de se synchroniser entre plusieurs tâches terminées.)
Dans Swift 4,
func executeMultiTask() {
//1. Create group
let taskGroup = DispatchGroup()
//2. Enter group
taskGroup.enter()
myTask1.execute(completeHandler: {
// ...
//3. Leave group
taskGroup.leave() //< balance with taskGroup.enter()
})
/* Add more tasks ...
//2. Enter group
taskGroup.enter()
myTask2.execute(completeHandler: {
//3. Leave group
defer {
// Use `defer` to make sure, `leave()` calls are balanced with `enter()`.
taskGroup.leave()
}
// ... more
})
*/
//4. Notify when all task completed at main thread queue.
taskGroup.notify(queue: .main) {
// All tasks are done.
// ...
})
}
Un exemple objectif-c de travail pour télécharger plusieurs fichiers
- (void) downloadFiles: (NSMutableArray *) fileArray : (NSString *)destParentDir{
dispatch_group_t serviceGroup = dispatch_group_create();
for (id fileInfo in fileArray) {
dispatch_group_enter(serviceGroup);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *fileName = [fileInfo valueForKey:@"name"];
//Create SubDirs if needed, note that you need to exclude file name for the dirsString :)
//[fileManager createDirectoryAtPath:dirsString withIntermediateDirectories:true attributes:nil error:NULL];
//Download file
NSURL *url = [NSURL URLWithString:@"YOUR_FILE_URL"];
NSData *urlData = [NSData dataWithContentsOfURL:url];
if(urlData)
{
NSString *localPath = [NSString stringWithFormat:@"%@/%@", destParentDir, fileName];
[urlData writeToFile:localPath atomically:YES];
}
dispatch_group_leave(serviceGroup);
}
dispatch_group_notify(serviceGroup, dispatch_get_main_queue(),^{
NSLog(@"Complete files download");
});
}
Tu devrais utiliser dispatch_group_t
. Veuillez vous référer à documentation Apple pour résoudre votre cas.