web-dev-qa-db-fra.com

En attente de plusieurs tâches de téléchargement asynchrones

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.

24
t4nhpt

Pour développer la réponse d'Abhinav, vous devez:

  1. Utilisez dispatch_group_create() pour créer un groupe.
  2. Appelez dispatch_group_enter(group) avant de démarrer chaque tâche de téléchargement.
  3. Appelez dispatch_group_leave(group) à l'intérieur du gestionnaire d'achèvement de la tâche.
  4. Appelez ensuite 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_asyncs 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.)

29
jtbandes

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.
         // ...   
     })

}
31
AechoLiu

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");
    });
}
3
Linerd

Tu devrais utiliser dispatch_group_t. Veuillez vous référer à documentation Apple pour résoudre votre cas.

2
Abhinav