Zoeken…


Syntaxis

  • Swift 3.0

  • DispatchQueue.main // Download de hoofdwachtrij

  • DispatchQueue (label: "my-serial-queue", kenmerken: [.serial, .qosBackground]) // Maak uw eigen seriële wachtrij

  • DispatchQueue.global (attributen: [.qosDefault]) // Toegang tot een van de wereldwijde gelijktijdige wachtrijen

  • DispatchQueue.main.async {...} // Stuur een taak asynchroon naar de hoofdthread

  • DispatchQueue.main.sync {...} // Verzend een taak synchroon met de hoofdthread

  • DispatchQueue.main.asyncAfter (deadline: .now () + 3) {...} // Stuur een taak asynchroon naar de hoofdthread die na x seconden moet worden uitgevoerd

  • Swift <3.0

  • dispatch_get_main_queue () // Zet de hoofdwachtrij op de hoofdthread

  • dispatch_get_global_queue (dispatch_queue_priority_t, 0) // Krijg globale wachtrij met gespecificeerde prioriteit dispatch_queue_priority_t

  • dispatch_async (dispatch_queue_t) {() -> Ongeldig in ...} // Een taak asynchroon verzenden op de opgegeven dispatch_queue_t

  • dispatch_sync (dispatch_queue_t) {() -> Ongeldig in ...} // Een taak synchroon verzenden op de opgegeven dispatch_queue_t

  • dispatch_after (dispatch_time (DISPATCH_TIME_NOW, Int64 (nanoseconden)), dispatch_queue_t, {...}); // Verzend een taak op de opgegeven dispatch_queue_t na nanoseconden

Een wachtrij voor Grand Central Dispatch (GCD) verkrijgen

Grand Central Dispatch werkt volgens het concept van "Dispatch Queues". Een verzendwachtrij voert taken uit die u aanwijst in de volgorde waarin ze worden doorgegeven. Er zijn drie soorten verzendwachtrijen:

  • Seriële verzendwachtrijen (ook wel privéverzendwachtrijen genoemd) voeren één taak tegelijk uit, in volgorde. Ze worden vaak gebruikt om de toegang tot een bron te synchroniseren.
  • Gelijktijdige verzendwachtrijen (ook wel globale verzendwachtrijen genoemd) voeren een of meer taken tegelijkertijd uit.
  • De hoofdverzendwachtrij voert taken uit op de hoofdthread.

Toegang krijgen tot de hoofdwachtrij:

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

Het systeem biedt gelijktijdige wereldwijde verzendwachtrijen (globaal voor uw toepassing), met verschillende prioriteiten. Je hebt toegang tot deze wachtrijen met de klasse DispatchQueue in Swift 3:

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

gelijk aan

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

In iOS 8 of hoger zijn de mogelijke servicekwaliteitswaarden die kunnen worden doorgegeven .userInteractive , .userInitiated , .default , .utility en .background . Deze vervangen de constanten DISPATCH_QUEUE_PRIORITY_ .

U kunt ook uw eigen wachtrijen maken met verschillende prioriteiten:

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)

In Swift 3 zijn wachtrijen die met deze initialisatie zijn gemaakt standaard serieel en het passeren van .workItem voor .workItem frequentie zorgt ervoor dat voor elk werkitem een autorelease-pool wordt gemaakt en leeggemaakt. Er is ook .never , wat betekent dat u zelf uw eigen autorelease-pools beheert, of .inherit die de instelling van de omgeving .inherit . In de meeste gevallen zult u waarschijnlijk .never Behalve in gevallen van extreme aanpassing gebruiken.

Taken uitvoeren in een Grand Central Dispatch (GCD) wachtrij

3.0

Gebruik de methoden sync , async en after om taken uit te voeren in een async .

Een taak asynchroon naar een wachtrij verzenden:

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

Een taak synchroon naar een wachtrij verzenden:

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

Een taak na een bepaald aantal seconden naar een wachtrij verzenden:

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

OPMERKING: Eventuele updates van de gebruikersinterface moeten via de hoofdthread worden aangeroepen! Zorg ervoor dat u de code voor UI-updates in DispatchQueue.main.async { ... } plaatst DispatchQueue.main.async { ... }

2.0

Soorten wachtrijen:

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)

Een taak asynchroon naar een wachtrij verzenden:

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

Een taak synchroon naar een wachtrij verzenden:

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

Om een taak na een tijdsinterval te verzenden (gebruik NSEC_PER_SEC om seconden om te zetten in nanoseconden):

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
}

Om een taak asynchroon uit te voeren en vervolgens de gebruikersinterface bij te werken:

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

OPMERKING: Eventuele updates van de gebruikersinterface moeten via de hoofdthread worden aangeroepen! Zorg ervoor dat u de code voor UI-updates in dispatch_async(dispatch_get_main_queue()) { ... } plaatst dispatch_async(dispatch_get_main_queue()) { ... }

Gelijktijdige lussen

GCD biedt een mechanisme voor het uitvoeren van een lus, waarbij de lussen gelijktijdig ten opzichte van elkaar plaatsvinden. Dit is erg handig bij het uitvoeren van een reeks rekenkundig dure berekeningen.

Overweeg deze lus:

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

U kunt die berekeningen tegelijkertijd uitvoeren met concurrentPerform (in Swift 3) of dispatch_apply (in 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
}

De lussluiting wordt voor elke index van 0 tot, maar exclusief iterations , aangeroepen. Deze iteraties worden gelijktijdig ten opzichte van elkaar uitgevoerd en dus is de volgorde waarin ze worden uitgevoerd niet gegarandeerd. Het werkelijke aantal iteraties dat tegelijkertijd op een bepaald moment plaatsvindt, wordt meestal bepaald door de mogelijkheden van het betreffende apparaat (bijvoorbeeld hoeveel kernen heeft het apparaat).

Een paar speciale overwegingen:

  • De concurrentPerform / dispatch_apply kan de lussen tegelijkertijd ten opzichte van elkaar uitvoeren, maar dit gebeurt allemaal synchroon met betrekking tot de thread van waaruit u het aanroept. Noem dit dus niet vanuit de hoofdthread, omdat dit die thread blokkeert totdat de lus is voltooid.

  • Omdat deze lussen gelijktijdig ten opzichte van elkaar plaatsvinden, bent u verantwoordelijk voor de draadveiligheid van de resultaten. Als u bijvoorbeeld een woordenboek bijwerkt met de resultaten van deze rekenkrachtige berekeningen, moet u deze updates zelf synchroniseren.

  • Let op, er is wat overhead verbonden aan het uitvoeren van gelijktijdige lussen. Dus als de berekeningen die binnen de lus worden uitgevoerd niet voldoende rekenintensief zijn, kan het zijn dat de prestaties die worden verkregen door gelijktijdige lussen te gebruiken, kunnen worden verminderd of zelfs volledig kunnen worden gecompenseerd door de overhead die is gekoppeld aan het synchroniseren van al deze gelijktijdige threads.

    U bent dus verantwoordelijk voor het bepalen van de juiste hoeveelheid werk die moet worden uitgevoerd in elke iteratie van de lus. Als de berekeningen te eenvoudig zijn, kunt u "schrijden" gebruiken om meer werk per lus op te nemen. In plaats van een gelijktijdige lus te maken met 1 miljoen triviale berekeningen, kunt u bijvoorbeeld 100 iteraties in uw lus uitvoeren en 10.000 berekeningen per lus uitvoeren. Op die manier wordt er voldoende werk verricht aan elke thread, zodat de overhead geassocieerd met het beheer van deze gelijktijdige lussen minder belangrijk wordt.

Taken uitvoeren in een OperationQueue

U kunt een OperationQueue als een lijn met taken die wachten om te worden uitgevoerd. In tegenstelling tot verzendwachtrijen in GCD, zijn bedieningswachtrijen geen FIFO (first-in-first-out). In plaats daarvan voeren ze taken uit zodra ze klaar zijn om te worden uitgevoerd, zolang er voldoende systeembronnen zijn om dit toe te staan.

Download de hoofd OperationQueue :

3.0
let mainQueue = OperationQueue.main

Maak een aangepaste OperationQueue :

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

Quality of Service specificeert het belang van het werk, of hoeveel de gebruiker waarschijnlijk op onmiddellijke resultaten van de taak rekent.

Een Operation aan een OperationQueue :

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

queue.addOperation(operation)

Voeg een blok toe aan een OperationQueue :

3.0
myQueue.addOperation {
    // some task
}

Voeg meerdere Operation aan een OperationQueue :

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

myQueue.addOperation(operations)

Stel in hoeveel Operation tegelijkertijd in de wachtrij mogen worden uitgevoerd:

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

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

Als u een wachtrij onderbreekt, wordt voorkomen dat deze de uitvoering start van bestaande, niet-gestarte bewerkingen of van nieuwe bewerkingen die aan de wachtrij zijn toegevoegd. De manier om deze wachtrij te hervatten, is door de isSuspended terug te zetten op false :

3.0
myQueue.isSuspended = true

// Re-enable execution
myQueue.isSuspended = false

Het opschorten van een OperationQueue stopt of annuleert geen bewerkingen die al worden uitgevoerd. Je moet alleen proberen een wachtrij die je hebt gemaakt te onderbreken, geen algemene wachtrijen of de hoofdwachtrij.

Bewerkingen op hoog niveau creëren

Het Foundation-framework biedt het Operation , dat een object op hoog niveau vertegenwoordigt dat een deel van het werk omvat dat in een wachtrij kan worden uitgevoerd. Niet alleen coördineert de wachtrij de prestaties van die bewerkingen, maar u kunt ook afhankelijkheden tussen bewerkingen vaststellen, annuleerbare bewerkingen maken, de mate van concurrency beperken die door de bewerkingswachtrij wordt gebruikt, enz.

Operation worden gereed om uit te voeren wanneer alle afhankelijkheden zijn voltooid. De eigenschap isReady dan gewijzigd in true .

Maak een eenvoudige niet-gelijktijdige Operation Subklasse:

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
    }

}

Voeg een bewerking toe aan een OperationQueue :

1.0
myQueue.addOperation(operation)

Hiermee wordt de bewerking tegelijkertijd in de wachtrij uitgevoerd.

Beheer afhankelijkheden van een Operation .

Afhankelijkheden definiëren andere Operation die moeten worden uitgevoerd in een wachtrij voordat die Operation als gereed voor uitvoering wordt beschouwd.

1.0
operation2.addDependency(operation1)

operation2.removeDependency(operation1)

Voer een Operation zonder wachtrij:

1.0
   operation.start()

Afhankelijkheden worden genegeerd. Als dit een gelijktijdige operatie, de taak kan nog steeds worden gelijktijdig uitgevoerd als de start methode offloads werken op de achtergrond wachtrijen.

Gelijktijdige operaties.

Als de taak die een Operation moet uitvoeren zelf asynchroon is (bijvoorbeeld een URLSession gegevenstaak), moet u de Operation als een gelijktijdige bewerking implementeren. In dit geval uw isAsynchronous moet implementatie terugkeren true , zou je hebben over het algemeen start methode die voert enkele setup, roept vervolgens de main methode die de taak daadwerkelijk uitvoert.

Wanneer de implementatie van een asynchrone Operation begint, moet u isExecuting , isFinished methoden en KVO implementeren. Dus, wanneer de uitvoering start, isExecuting eigenschapExecuting in true . Wanneer een Operation zijn taak isExecuting is isExecuting ingesteld op false en is isFinished ingesteld op true . Als de bewerking wordt geannuleerd, wordt zowel isCancelled als isFinished gewijzigd in true . Al deze eigenschappen zijn waarneembaar met de sleutelwaarde.

Een Operation annuleren.

Als cancel isCancelled eigenschap isCancelled eenvoudig gewijzigd in true . Om te reageren op annulering vanuit uw eigen Operation subklasse, moet u de waarde van isCancelled minstens periodiek binnen de main en op de juiste manier reageren.

1.0
operation.cancel()


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow