Szukaj…


Składnia

  • Swift 3.0

  • DispatchQueue.main // Pobierz kolejkę główną

  • DispatchQueue (etykieta: „moja kolejka szeregowa”, atrybuty: [.serial, .qosBackground]) // Utwórz własną prywatną kolejkę szeregową

  • DispatchQueue.global (atrybuty: [.qosDefault]) // Uzyskaj dostęp do jednej z globalnych współbieżnych kolejek

  • DispatchQueue.main.async {...} // Wyślij zadanie asynchronicznie do głównego wątku

  • DispatchQueue.main.sync {...} // Wyślij zadanie synchronicznie do głównego wątku

  • DispatchQueue.main.asyncAfter (termin: .now () + 3) {...} // Wyślij zadanie asynchronicznie do głównego wątku, który ma zostać wykonany po x sekundach

  • Szybki <3,0

  • dispatch_get_main_queue () // Uruchom kolejkę główną w głównym wątku

  • dispatch_get_global_queue (dispatch_queue_priority_t, 0) // Uzyskaj kolejkę globalną o określonym priorytecie dispatch_queue_priority_t

  • dispatch_async (dispatch_queue_t) {() -> Void in ...} // Wyślij zadanie asynchronicznie na podanym dispatch_queue_t

  • dispatch_sync (dispatch_queue_t) {() -> Void in ...} // Wyślij zadanie synchronicznie na podanym dispatch_queue_t

  • dispatch_after (dispatch_time (DISPATCH_TIME_NOW, Int64 (nanosekundy)), dispatch_queue_t, {...}); // Wyślij zadanie na określony dispque_queue_t po nanosekundach

Uzyskiwanie kolejki Grand Central Dispatch (GCD)

Grand Central Dispatch pracuje nad koncepcją „Kolejki wysyłkowe”. Kolejka wysyłkowa wykonuje wyznaczone zadania w kolejności, w jakiej zostały przekazane. Istnieją trzy typy kolejek wysyłkowych:

  • Szeregowe kolejki wysyłkowe ( znane również jako prywatne kolejki wysyłkowe) wykonują kolejno jedno zadanie. Są często używane do synchronizacji dostępu do zasobu.
  • Współbieżne kolejki wysyłkowe (inaczej globalne kolejki wysyłkowe) wykonują jedno lub więcej zadań jednocześnie.
  • Główna kolejka wysyłkowa wykonuje zadania w głównym wątku.

Aby uzyskać dostęp do głównej kolejki:

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

System zapewnia współbieżne globalne kolejki wysyłki (globalne dla aplikacji) o różnych priorytetach. Dostęp do tych kolejek można uzyskać za pomocą klasy DispatchQueue w Swift 3:

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

równoważny

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

W systemie iOS 8 lub nowszym możliwe wartości jakości usług, które można przekazać, to .userInteractive , .userInitiated , .default , .utility i .background . Zastępują one stałe DISPATCH_QUEUE_PRIORITY_ .

Możesz także tworzyć własne kolejki o różnych priorytetach:

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)

W Swift 3 kolejki tworzone są z tego initializer seryjny domyślnie i przechodzącej .workItem dla autorelease częstotliwości zapewnia jest tworzona i odsączone dla każdej pozycji roboczej basen autorelease. Istnieje również .never , co oznacza, że będziesz sam zarządzał własnymi pulami .inherit lub .inherit które dziedziczy ustawienia ze środowiska. W większości przypadków prawdopodobnie nie będziesz używać. .never z wyjątkiem przypadków skrajnego dostosowania.

Uruchamianie zadań w kolejce Grand Central Dispatch (GCD)

3.0

Aby uruchomić zadania w kolejce wysyłki, użyj metod sync , async i after .

Aby asynchronicznie wysłać zadanie do kolejki:

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

Aby synchronicznie wysłać zadanie do kolejki:

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

Aby wysłać zadanie do kolejki po określonej liczbie sekund:

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

UWAGA: Wszelkie aktualizacje interfejsu użytkownika powinny być wywoływane w głównym wątku! Upewnij się, że umieściłeś kod aktualizacji interfejsu użytkownika w DispatchQueue.main.async { ... }

2.0

Rodzaje kolejki:

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)

Aby asynchronicznie wysłać zadanie do kolejki:

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

Aby synchronicznie wysłać zadanie do kolejki:

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

Aby wysłać zadanie po upływie określonego czasu (użyj NSEC_PER_SEC aby przekonwertować sekundy na nanosekundy):

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
}

Aby wykonać zadanie asynchronicznie i zaktualizować interfejs użytkownika:

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

UWAGA: Wszelkie aktualizacje interfejsu użytkownika powinny być wywoływane w głównym wątku! Upewnij się, że umieściłeś kod aktualizacji interfejsu użytkownika wewnątrz dispatch_async(dispatch_get_main_queue()) { ... }

Równoległe pętle

GCD zapewnia mechanizm wykonywania pętli, dzięki czemu pętle występują równolegle względem siebie. Jest to bardzo przydatne podczas wykonywania serii drogich obliczeniowo obliczeń.

Rozważ tę pętlę:

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

Możesz wykonać te obliczenia jednocześnie, używając concurrentPerform (w Swift 3) lub dispatch_apply (w 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
}

Zamknięcie pętli będzie wywoływane dla każdego index od 0 do iterations , ale bez uwzględnienia. Te iteracje będą przebiegać równolegle względem siebie, a zatem kolejność ich uruchamiania nie jest gwarantowana. Rzeczywista liczba iteracji, które zachodzą jednocześnie w danym momencie, jest ogólnie podyktowana możliwościami danego urządzenia (np. Ile rdzeni ma to urządzenie).

Kilka specjalnych uwag:

  • concurrentPerform / dispatch_apply może uruchamiać pętle jednocześnie względem siebie, ale wszystko to dzieje się synchronicznie w odniesieniu do wątku, z którego go wywołujesz. Nie wywołuj tego z głównego wątku, ponieważ spowoduje to zablokowanie tego wątku, dopóki pętla nie zostanie wykonana.

  • Ponieważ pętle te zachodzą równolegle względem siebie, jesteś odpowiedzialny za zapewnienie bezpieczeństwa wątków wyników. Na przykład, jeśli aktualizujesz jakiś słownik o wyniki tych kosztownie obliczeniowych obliczeń, upewnij się, że synchronizujesz te aktualizacje samodzielnie.

  • Uwaga: podczas uruchamiania równoległych pętli występuje pewien narzut. Tak więc, jeśli obliczenia wykonywane w pętli nie są wystarczająco intensywne obliczeniowo, może się okazać, że wszelka wydajność uzyskana przy użyciu współbieżnych pętli może zostać zmniejszona, jeśli nie całkowicie, zrównoważona przez narzut związany z synchronizacją wszystkich tych współbieżnych wątków.

    Odpowiadasz więc za określenie prawidłowej ilości pracy do wykonania w każdej iteracji pętli. Jeśli obliczenia są zbyt proste, możesz zastosować „kroczenie”, aby uwzględnić więcej pracy na pętlę. Na przykład, zamiast wykonywać równoległą pętlę z 1 milionem trywialnych obliczeń, możesz wykonać 100 iteracji w swojej pętli, wykonując 10 000 obliczeń na pętlę. W ten sposób wystarczająca ilość pracy jest wykonywana na każdym wątku, więc narzut związany z zarządzaniem tymi równoległymi pętlami staje się mniej znaczący.

Uruchamianie zadań w OperationQueue

Możesz myśleć o OperationQueue jako o linii zadań oczekujących na wykonanie. W przeciwieństwie do kolejek wysyłkowych w GCD, kolejki operacji nie są FIFO (pierwsze weszło pierwsze wyszło). Zamiast tego wykonują zadania, gdy tylko są gotowe do wykonania, o ile jest wystarczających zasobów systemowych, aby na to pozwolić.

Uzyskaj główną OperationQueue :

3.0
let mainQueue = OperationQueue.main

Utwórz niestandardową kolejkę OperationQueue :

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

Jakość usługi określa ważność pracy lub to, ile użytkownik może liczyć na natychmiastowe wyniki zadania.

Dodaj Operation do OperationQueue :

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

queue.addOperation(operation)

Dodaj blok do OperationQueue :

3.0
myQueue.addOperation {
    // some task
}

Dodaj wiele Operation do OperationQueue :

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

myQueue.addOperation(operations)

Dostosuj liczbę Operation które mogą być wykonywane jednocześnie w kolejce:

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

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

Zawieszenie kolejki uniemożliwi jej rozpoczęcie wykonywania wszelkich istniejących, niezakończonych operacji lub jakichkolwiek nowych operacji dodanych do kolejki. Sposób na wznowienie tej kolejki polega na ustawieniu isSuspended powrotem na false :

3.0
myQueue.isSuspended = true

// Re-enable execution
myQueue.isSuspended = false

Zawieszenie OperationQueue nie zatrzymuje ani nie anuluje operacji, które już są wykonywane. Należy jedynie próbować zawiesić utworzoną przez siebie kolejkę, a nie kolejki globalne lub kolejkę główną.

Tworzenie operacji wysokiego poziomu

Framework Foundation udostępnia typ Operation , który reprezentuje obiekt wysokiego poziomu, który obejmuje część pracy, którą można wykonać w kolejce. Kolejka nie tylko koordynuje wydajność tych operacji, ale można także ustalić zależności między operacjami, tworzyć operacje, które można anulować, ograniczać stopień współbieżności stosowanej przez kolejkę operacji itp.

Operation jest gotowa do wykonania po zakończeniu wykonywania wszystkich jej zależności. Następnie właściwość isReady zmienia się na true .

Utwórz prostą niesąsiadującą podklasę Operation :

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
    }

}

Dodaj operację do OperationQueue :

1.0
myQueue.addOperation(operation)

Spowoduje to wykonanie operacji równolegle w kolejce.

Zarządzaj zależnościami od Operation .

Zależności definiują inne Operation które muszą zostać wykonane w kolejce, zanim Operation zostanie uznana za gotową do wykonania.

1.0
operation2.addDependency(operation1)

operation2.removeDependency(operation1)

Uruchom Operation bez kolejki:

1.0
   operation.start()

Zależności zostaną zignorowane. Jeśli jest to operacja współbieżna, zadanie może być nadal wykonywane jednocześnie, jeśli jego metoda start odciąża pracę do kolejek w tle.

Współbieżne operacje.

Jeśli zadanie, które ma wykonać Operation , samo w sobie jest asynchroniczne (np. URLSession danych URLSession ), należy zaimplementować Operation jako operację współbieżną. W takim przypadku twoja implementacja isAsynchronous powinna zwrócić true , na ogół masz metodę start , która wykonuje pewne ustawienia, a następnie wywołuje swoją main metodę, która faktycznie wykonuje zadanie.

Przy wdrażaniu asynchroniczny Operation rozpoczyna trzeba wdrożyć isExecuting , isFinished metod i KVO. Kiedy więc rozpoczyna się wykonywanie, właściwość isExecuting zmienia się na true . Gdy Operation zakończy swoje zadanie, parametr isExecuting ma wartość false , a parametr isFinished ma wartość true . Jeśli operacja zostanie anulowana, zarówno isCancelled jak i isFinished zmieni się na true . Wszystkie te właściwości są obserwowalne.

Anuluj Operation .

Wywołanie cancel po prostu zmienia właściwość isCancelled na true . Aby zareagować na anulowanie w ramach własnej podklasy Operation , należy co najmniej okresowo sprawdzać wartość isCancelled w main i odpowiednio reagować.

1.0
operation.cancel()


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow