ios - grand - multithreading swift 4
Esperando mĂșltiples tareas de descarga asĂncronas (4)
Quiero descargar algunos archivos, por ejemplo, 100 archivos, al mismo tiempo. Así que decidí agregar mis subprocesos de descarga a una cola de envío y GCD ajustará cuántos subprocesos se ejecutarán al mismo tiempo.
El problema aquí es: el bloque en dispatch_async
se completará inmediatamente, porque la task
se ejecutará en otro hilo. Entonces, si la longitud de las urls
es 100, creará 100 hilos inmediatamente.
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()
}
}
¿Cómo puedo configurar el bloque en dispatch_async
para esperar a que se complete la tarea de descarga? No quiero usar dispatch_semaphore
, ya que solo permite ejecutar una tarea de descarga al mismo tiempo.
Debes usar dispatch_group_t
. Consulte la documentación de Apple para solucionar su caso.
En Swift3,
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
taskGroup.notify(queue: DispatchQueue.main, work: DispatchWorkItem(block: {
// All tasks are done.
// ...
})
}
Para ampliar la respuesta de Abhinav, debes:
- Use
dispatch_group_create()
para crear un grupo. - Llame a
dispatch_group_enter(group)
antes de comenzar cada tarea de descarga. - Llame a
dispatch_group_leave(group)
dentro del controlador de finalización de la tarea. - Luego llame a
dispatch_group_notify(group, queue, ^{ ... })
para poner en cola un bloque que se ejecutará cuando se completen todas las tareas.
Puedes ver un ejemplo en esta publicación .
(Por cierto, no es cierto que hacer 100 dispatch_async
s en una fila creará 100 subprocesos inmediatamente. El sistema aún conserva el control sobre cuántos subprocesos usar para satisfacer la cola. Sin embargo, su código no espera ninguna de las tareas para completar antes de que regrese, ni tampoco intenta sincronizar entre varias tareas completadas.)
Un ejemplo de trabajo objetivo-c para descargar archivos múltiples
- (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");
});
}