web-dev-qa-db-ja.com

複数の非同期ダウンロードタスクを待機しています

いくつかのファイル、たとえば100個のファイルを同時にダウンロードしたい。そこで、ダウンロードスレッドをディスパッチキューに追加すると、GCDが同時に実行するスレッドの数を調整します。

ここでの問題は、taskが別のスレッドで実行されるため、dispatch_asyncのブロックがすぐに完了することです。したがって、urlsの長さが100の場合、すぐに100個のスレッドが作成されます。

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()
    }
}

ダウンロードタスクの完了を待つためにdispatch_asyncのブロックを設定するにはどうすればよいですか?dispatch_semaphoreを使用したくありません。同時。

24
t4nhpt

Abhinavの答えを拡張するには、以下を行う必要があります。

  1. dispatch_group_create()を使用してグループを作成します。
  2. 各ダウンロードタスクを開始する前に、dispatch_group_enter(group)を呼び出します。
  3. タスクの完了ハンドラー内でdispatch_group_leave(group)を呼び出します。
  4. 次に、dispatch_group_notify(group, queue, ^{ ... })を呼び出して、すべてのタスクが完了したときに実行されるブロックをキューに入れます。

this post で例を見ることができます。

(ところで、100 dispatch_asyncsが連続すると、すぐに100個のスレッドが作成されます。システムは、キューを満たすために使用するスレッドの数を引き続き制御します。ただし、コードはタスクが完了するまで待機せずに戻り、複数のタスクの完了を同期しようとしません。)

29
jtbandes

In 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

マルチファイルをダウンロードするための実用的なObjective-Cの例

- (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

dispatch_group_tを使用する必要があります。 Appleドキュメント を参照して、ケースを解決してください。

2
Abhinav