Recherche…


Syntaxe

  • Swift 3.0

  • DispatchQueue.main // Récupère la file d'attente principale

  • DispatchQueue (label: "my-serial-queue", attributs: [.serial, .qosBackground]) // Crée votre propre file d'attente série privée

  • DispatchQueue.global (attributs: [.qosDefault]) // Accéder à l'une des files d'attente simultanées globales

  • DispatchQueue.main.async {...} // Envoie une tâche de manière asynchrone au thread principal

  • DispatchQueue.main.sync {...} // Envoie une tâche de manière synchrone au thread principal

  • DispatchQueue.main.asyncAfter (date limite: .now () + 3) {...} // Envoie une tâche de manière asynchrone au thread principal à exécuter après x secondes

  • Swift <3.0

  • dispatch_get_main_queue () // Récupère la file d'attente principale sur le thread principal

  • dispatch_get_global_queue (dispatch_queue_priority_t, 0) // Récupère la file d'attente globale avec la priorité spécifiée dispatch_queue_priority_t

  • dispatch_async (dispatch_queue_t) {() -> Void in ...} // Envoie une tâche de manière asynchrone sur le dispatch_queue_t spécifié

  • dispatch_sync (dispatch_queue_t) {() -> Void in ...} // Envoie une tâche de manière synchrone sur le dispatch_queue_t spécifié

  • dispatch_after (dispatch_time (DISPATCH_TIME_NOW, Int64 (nanosecondes)), dispatch_queue_t, {...}); // Envoie une tâche sur le dispatch_queue_t spécifié après des nanosecondes

Obtention d'une file d'attente Grand Central Dispatch (GCD)

Grand Central Dispatch travaille sur le concept de "files d'attente d'expédition". Une file d'attente de distribution exécute les tâches que vous avez désignées dans l'ordre dans lequel elles ont été passées. Il existe trois types de files d'attente:

  • Serial Dispatch Queues (aka files d'attente de distribution privées) exécutent une tâche à la fois, dans l'ordre. Ils sont fréquemment utilisés pour synchroniser l'accès à une ressource.
  • Les files d'attente de répartition simultanées ( c.-à-d . Les files d'attente de répartition globales) exécutent une ou plusieurs tâches simultanément.
  • La file d'attente de répartition principale exécute les tâches sur le thread principal.

Pour accéder à la file d'attente principale:

3.0
let mainQueue = DispatchQueue.main
3.0
let mainQueue = dispatch_get_main_queue()

Le système fournit des files d'attente de répartition mondiales simultanées (globales à votre application), avec des priorités variables. Vous pouvez accéder à ces files d'attente en utilisant la classe DispatchQueue dans Swift 3:

3.0
let globalConcurrentQueue = DispatchQueue.global(qos: .default)

équivalent à

let globalConcurrentQueue = DispatchQueue.global()
3.0
let globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

Dans iOS 8 ou version ultérieure, les valeurs de qualité de service pouvant être transmises sont les .userInteractive : .userInitiated , .default , .utility , .background et .background . Ceux-ci remplacent les constantes DISPATCH_QUEUE_PRIORITY_ .

Vous pouvez également créer vos propres files d'attente avec différentes priorités:

3.0
let myConcurrentQueue = DispatchQueue(label: "my-concurrent-queue", qos: .userInitiated, attributes: [.concurrent], autoreleaseFrequency: .workItem, target: nil)
let mySerialQueue = DispatchQueue(label: "my-serial-queue", qos: .background, attributes: [], autoreleaseFrequency: .workItem, target: nil)
3.0
let myConcurrentQueue = dispatch_queue_create("my-concurrent-queue", DISPATCH_QUEUE_CONCURRENT)
let mySerialQueue = dispatch_queue_create("my-serial-queue", DISPATCH_QUEUE_SERIAL)

Dans Swift 3, les files d'attente créées avec cet initialiseur sont en série par défaut et le passage de .workItem à la fréquence d'autorelease garantit qu'un pool d'autorelease est créé et vidé pour chaque élément de travail. Il y a aussi .never , ce qui signifie que vous allez gérer vous-même vos pools d'autorelease, ou .inherit qui hérite des paramètres de l'environnement. Dans la plupart des cas, vous n'utiliserez probablement jamais .never sauf en cas de personnalisation extrême.

Exécution de tâches dans une file d'attente Grand Central Dispatch (GCD)

3.0

Pour exécuter des tâches sur une file d'attente de distribution, utilisez les méthodes sync , async et after .

Pour envoyer une tâche dans une file d'attente de manière asynchrone:

let queue = DispatchQueue(label: "myQueueName")

queue.async {
    //do something
    
    DispatchQueue.main.async {
        //this will be called in main thread
        //any UI updates should be placed here
    }
}
// ... code here will execute immediately, before the task finished

Pour envoyer une tâche dans une file d'attente de manière synchrone:

queue.sync {
    // Do some task
}
// ... code here will not execute until the task is finished

Pour envoyer une tâche dans une file d'attente après un certain nombre de secondes:

queue.asyncAfter(deadline: .now() + 3) {
    //this will be executed in a background-thread after 3 seconds
}
// ... code here will execute immediately, before the task finished

REMARQUE: Toute mise à jour de l'interface utilisateur doit être appelée sur le thread principal! Assurez-vous de mettre le code des mises à jour d'interface utilisateur dans DispatchQueue.main.async { ... }

2.0

Types de file d'attente:

let mainQueue = dispatch_get_main_queue()
let highQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
let backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)

Pour envoyer une tâche dans une file d'attente de manière asynchrone:

dispatch_async(queue) {
    // Your code run run asynchronously. Code is queued and executed 
    // at some point in the future.
}
// Code after the async block will execute immediately

Pour envoyer une tâche dans une file d'attente de manière synchrone:

dispatch_sync(queue) {
    // Your sync code
}
// Code after the sync block will wait until the sync task finished

Pour envoyer une tâche après un intervalle de temps (utilisez NSEC_PER_SEC pour convertir les secondes en nanosecondes):

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
    // Code to be performed in 2.5 seconds here
}

Pour exécuter une tâche de manière asynchrone et mettre à jour l'interface utilisateur:

dispatch_async(queue) {
    // Your time consuming code here
    dispatch_async(dispatch_get_main_queue()) {
        // Update the UI code 
    }
}

REMARQUE: Toute mise à jour de l'interface utilisateur doit être appelée sur le thread principal! Assurez-vous de mettre le code des mises à jour de l'interface utilisateur dans dispatch_async(dispatch_get_main_queue()) { ... }

Boucles simultanées

GCD fournit un mécanisme pour effectuer une boucle, les boucles se produisant simultanément les unes par rapport aux autres. Ceci est très utile lorsque vous effectuez une série de calculs coûteux.

Considérez cette boucle:

for index in 0 ..< iterations {
    // Do something computationally expensive here
}

Vous pouvez effectuer ces calculs simultanément à l'aide de concurrentPerform (dans Swift 3) ou de dispatch_apply (dans Swift 2):

3.0
DispatchQueue.concurrentPerform(iterations: iterations) { index in
    // Do something computationally expensive here
}
3.0
dispatch_apply(iterations, queue) { index in
    // Do something computationally expensive here
}

La fermeture de la boucle sera appelée pour chaque index entre 0 et, mais sans inclure, les iterations . Ces itérations seront exécutées simultanément les unes par rapport aux autres et, par conséquent, l'ordre qu'elles exécutent n'est pas garanti. Le nombre réel d'itérations qui se produisent simultanément à un moment donné est généralement dicté par les capacités du périphérique en question (par exemple, le nombre de cœurs du périphérique).

Quelques considérations spéciales:

  • concurrentPerform / dispatch_apply peut exécuter les boucles simultanément les unes par rapport aux autres, mais tout cela se produit de manière synchrone par rapport au thread à partir duquel vous l'appelez. Donc, n'appelez pas cela depuis le thread principal, car cela bloquera ce thread jusqu'à ce que la boucle soit terminée.

  • Étant donné que ces boucles se produisent simultanément les unes par rapport aux autres, vous êtes responsable de la sécurité des threads. Par exemple, si vous mettez à jour un dictionnaire avec les résultats de ces calculs coûteux, veillez à synchroniser ces mises à jour vous-même.

  • Notez qu'il existe des frais généraux associés à l'exécution de boucles concurrentes. Par conséquent, si les calculs effectués à l'intérieur de la boucle ne nécessitent pas beaucoup de calculs, vous pouvez constater que les performances obtenues en utilisant des boucles simultanées peuvent être diminuées, voire totalement compensées, par la surcharge associée à la synchronisation de tous ces threads.

    Vous êtes donc responsable de déterminer la quantité correcte de travail à effectuer dans chaque itération de la boucle. Si les calculs sont trop simples, vous pouvez utiliser "striding" pour inclure plus de travail par boucle. Par exemple, plutôt que de faire une boucle simultanée avec 1 million de calculs triviaux, vous pouvez effectuer 100 itérations dans votre boucle, en effectuant 10 000 calculs par boucle. De cette façon, il y a suffisamment de travail effectué sur chaque thread, de sorte que la surcharge associée à la gestion de ces boucles simultanées devient moins importante.

Exécution de tâches dans une OperationQueue

Vous pouvez penser à OperationQueue comme une ligne de tâches en attente d'exécution. Contrairement aux files d'attente d'expédition dans GCD, les files d'attente d'opérations ne sont pas des FIFO (premier entré, premier sorti). Au lieu de cela, ils exécutent des tâches dès qu'ils sont prêts à être exécutés, tant qu'il y a suffisamment de ressources système pour le permettre.

Obtenez le principal OperationQueue :

3.0
let mainQueue = OperationQueue.main

Créez une OperationQueue personnalisée:

3.0
let queue = OperationQueue()
queue.name = "My Queue"
queue.qualityOfService = .default

Qualité de service spécifie l’importance du travail ou la probabilité que l’utilisateur compte sur les résultats immédiats de la tâche.

Ajouter une Operation à une OperationQueue :

3.0
// An instance of some Operation subclass
let operation = BlockOperation {
    // perform task here
}

queue.addOperation(operation)

Ajouter un bloc à OperationQueue :

3.0
myQueue.addOperation {
    // some task
}

Ajoutez plusieurs Operation à une OperationQueue :

3.0
let operations = [Operation]()
// Fill array with Operations

myQueue.addOperation(operations)

Ajustez le nombre d' Operation pouvant être exécutées simultanément dans la file d'attente:

myQueue.maxConcurrentOperationCount = 3 // 3 operations may execute at once

// Sets number of concurrent operations based on current system conditions
myQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount

La suspension d'une file d'attente l'empêchera de lancer l'exécution d'opérations existantes non démarrées ou de nouvelles opérations ajoutées à la file d'attente. La manière de reprendre cette file d'attente consiste à définir isSuspended sur false :

3.0
myQueue.isSuspended = true

// Re-enable execution
myQueue.isSuspended = false

La suspension d'une OperationQueue n'arrête pas ou n'annule pas les opérations en cours d'exécution. On ne doit tenter de suspendre une file d'attente que vous avez créée, pas les files d'attente globales ou la file d'attente principale.

Création d'opérations de haut niveau

Le framework Foundation fournit le type Operation , qui représente un objet de haut niveau qui encapsule une partie du travail pouvant être exécutée dans une file d'attente. Non seulement la file d'attente coordonne les performances de ces opérations, mais vous pouvez également établir des dépendances entre les opérations, créer des opérations annulables, limiter le degré de concurrence utilisé par la file d'attente d'opérations, etc.

Operation deviennent prêtes à être exécutées lorsque toutes ses dépendances sont terminées. La propriété isReady alors true .

Créez une sous-classe Operation simple non concurrente:

3.0
class MyOperation: Operation {

    init(<parameters>) {
        // Do any setup work here
    }

    override func main() {
        // Perform the task
    }

}
2.3
class MyOperation: NSOperation {

    init(<parameters>) {
        // Do any setup work here
    }

    override func main() {
        // Perform the task
    }

}

Ajouter une opération à une OperationQueue :

1.0
myQueue.addOperation(operation)

Cela exécutera l'opération simultanément dans la file d'attente.

Gérer les dépendances sur une Operation .

Les dépendances définissent d'autres Operation qui doivent s'exécuter dans une file d'attente avant que l' Operation soit considérée prête à être exécutée.

1.0
operation2.addDependency(operation1)

operation2.removeDependency(operation1)

Exécutez une Operation sans file d'attente:

1.0
   operation.start()

Les dépendances seront ignorées. S'il s'agit d'une opération simultanée, la tâche peut toujours être exécutée simultanément si sa méthode de start décharge le travail sur les files d'attente en arrière-plan.

Opérations simultanées

Si la tâche que l' Operation consiste à effectuer est, lui - même, asynchrone, (par exemple , une URLSession tâche de données), vous devez mettre en œuvre l' Operation comme une opération concurrente. Dans ce cas, votre implémentation isAsynchronous doit retourner true , vous aurez généralement une méthode start qui effectue une configuration, puis appelle sa méthode main qui exécute réellement la tâche.

Lorsque vous implémentez une Operation asynchrone, vous devez implémenter les méthodes isExecuting , isFinished et KVO. Ainsi, lorsque l'exécution commence, la propriété isExecuting devient true . Lorsqu'une Operation termine sa tâche, isExecuting est défini sur false et isFinished est défini sur true . Si l'opération est annulée, isCancelled et isFinished true . Toutes ces propriétés sont observables par valeur-clé.

Annuler une Operation .

L'appel d' cancel simplement la propriété isCancelled sur true . Pour répondre à l'annulation depuis votre propre sous-classe Operation , vous devez vérifier la valeur de isCancelled au moins périodiquement dans main et répondre de manière appropriée.

1.0
operation.cancel()


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow