Swift: O co chodzi z tymi kolejkami?

Nauka programownia

Opublikowany: Feb 17, 2019

Jeśli jesteście początkującymi programistami Swift i nie macie backgroundu w postaci nauki innych języków programowania, na pewno zastanowiło Was czym są wątki (threads) i kolejki (queues), o których otrzymaliście informację od Xcode w przypadku nieudanego wykonania jakiegoś fragmentu kodu.

OTO ŚPIESZĘ Z WYJAŚNIENIEM

Komputery (tak, iPhone i iPad to też komputery) już od jakiegoś czasu przestały przyspieszać. Tzn wciąż słyszym o procesorach taktowanych zegarami 2 i 3 gigaherce. A jeszcze kilkanaście lat temu podwojenie mocy procesorów następowało średnio raz na rok.

Brak zwiększania częstości zegara wynikł z pewnych ograniczeń fizycznych. Zamiast tego komputery otrzymały dostęp do wielu rdzeni procesorów. Znaczy to tyle, że fizycznie w procesorze jest dostępnych wiele podjednostek, które jednocześnie mogą prowadzić obliczenia.

I TU DOCHODZIMY DO WĄTKU WĄTKÓW

Żeby program mógł działać na takim procesorze, jego kod powinien być podzielony na takie fragmenty, które mogą wykonywać się równocześnie. Jakie to mogą być fragmenty? Nie trzbea długo szukać, żeby znaleźć przykłady czynności wykonywanych jednocecześnie: ś

  • Ściąganie pliku podczas przeglądania strony www.
  • Pobieranie piosenki podczas słuchania innej.
  • Planowanie drogi ucieczki antagonisty w grze podczas ataku gracza.
  • Mierzenie pulsu podczas sprawdzania godziny…

Ok. Część z tych przykładów dotyczy działania jednoczesnego różnyc aplikacji. Jednak idea pozostaje ta sama (chociaż uproszczona). Poszczególne czynności są wykonywane przez różne rdzenie procesora[1].

WĄTKI W PROGRAMOWANIU APLIKACJI DLA IOS

Jako programiści Swift możecie skorzystać z narzędzi tzw. Kolejek, które pomagają wykonywać czynności w innych wątkach. W takich kolejkach działających w tle powinniście uruchamiać wszystkie zadania, które wymagają trochę większych zasobów czasowych. Dzięki temu aplikacja będzie bardziej responsywna (czytaj: będzie działała lepiej i płynniej i więcej ludzi ją kupi).

Jak to zrobić?

Jest to bardzo proste. Kod, który ma wykonywać się w tle należy przekazać do odpowiedniej kolejki

let cQ = DispatchQueue(label: "nazwa")

Obiekt kolejki tworzony jest za pomocą konstrkutkra DispatchQueue. Taka kolejka jest domyślnie synchroniczna. To znaczy, że wszystkie operacje, które będą miały wykonywać się w niej asynchronicznie (niezależnie od głównego wątku) będą w niej wykonane po kolei.

Spróbujmy przekazać do tak stworzonej kolejki jakieś operacje. Jej działanie dobrze widać na przykładach pętli wypisujących coś na standardowe wyjście.

print("PRZED PRZEKAZANIEM ZADAŃ DO KOLEJKI")

cQ.sync {
    for i in 1 ... 10  {
        print("\(i) ++++")
    }
}

cQ.sync {
    for i in 1 ... 10  {
        print("\(i) ----")
    }
}
print("JUŻ PO PRZEKAZANIU ZADAŃ DO KOLEJKI")

Wywołanie synchroniczne spowodowało, że wynik jest łatwy do przewidzenia

PRZED PRZEKAZANIEM ZADAŃ DO KOLEJKI
1 ++++
2 ++++
3 ++++
4 ++++
5 ++++
1 ----
2 ----
3 ----
4 ----
5 ----

JUŻ PO PRZEKAZANIU ZADAŃ DO KOLEJKI

Widać, że kod, który jest poza nową kolejką (czyli linia wypisywana przed i po przekazaniu zadań do kolejki jest wykonana zgodnie ze spodziewaną kolejnością. Zatem główny fragment kodu czekał, aż zadania pętli się zakończą.

Jeśli zmienimy typ wywołania na async, okaże się, że zadania z pętli zaczną żyć własnym życiem, a wywołanie async nie spowoduje zablokowania głównego wątku.

PRZED PRZEKAZANIEM ZADAŃ DO KOLEJKI
1 ++++
2 ++++
JUŻ PO PRZEKAZANIU ZADAŃ DO KOLEJKI
3 ++++
4 ++++
5 ++++
1 ----
2 ----
3 ----
4 ----
5 ----

Jeszcze ciekawiej będzie, gdy pozwolimy obu zadaniom być realizowanym jednocześnie, zmieniając atrybuty nowo utworzonej kolejki.

let cQ = DispatchQueue(label: "nazwa",  attributes: .concurrent)

Wówczas pętle w wywołaniach ansyhcronicznych będą przenikały się, generując taki oto wynik.

PRZED PRZEKAZANIEM ZADAŃ DO KOLEJKI
1 ----
JUŻ PO PRZEKAZANIU ZADAŃ DO KOLEJKI
1 ++++
2 ----
3 ----
4 ----
2 ++++
5 ----
3 ++++
4 ++++
5 ++++

Ale co zrobić, gdybyśmy chcieli wiedzieć, kiedy instrukcji z kolejki zakończą się? Trzeba wrócić wtedy do głównego wątku i na przykład wywołać jakąś funkcję. W treści kodu przekazanego do funkcji async dodajemy więc:

DispatchQueue.main.sync {
        //Kod do wykonania w wątku głównym
    }

A w bloku sync możemy już zmodyfikować UI, lub wykonać kod odpowiedzialny za zagospodarowanie wyników uzyskanych w wątku w tle.

CZY TO WSZYSTKO?

Ten przykład nie wyczerpuje możliwości wątków i kolejek, a w szczególności pomija podstawowe aspekty synchronizacji tychże. Dużo więc jeszcze jest do odkrycia! Powodzenia!


dr Błażej Zyglarski

Autoryzowany Trener Apple (Swift), praktyk z wieloletnim doświadczeniem

Od lat pasjonat technologii mobilnych. Autor dziesiątek aplikacji dla systemów iOS, tvOS i watchOS. Wykładowca na Wydziale Matematyki i Informatyki Uniwersytetu Mikołaja Kopernika w Toruniu. Praktykujący deweloper iOS. Współzałożyciel Asuri Solutions.


Image
Felieton
Rozliczanie aplikacji sprzedanych w AppStore
Jun 10, 2019
Image
Felieton
Cały internet na płycie CD
Apr 01, 2019
Image
Nauka programownia
Swift: O co chodzi z tymi kolejkami?
Feb 17, 2019
Image
Felieton
Tim Cook docenił wzrost sprzedaży w Polsce
Feb 04, 2019
Image
Nauka programownia
Limits of testing
Nov 26, 2018

Nasze szkolenia

Image
Image
Programowanie aplikacji iOS w Swift 5
Dwudniowe szkolenie od podstaw
Toruń - 2019-09-21
dr Błażej Zyglarski
Image
Image
Wzorce projektowe w iOS
Trzydniowe szkolenie dla średniozaawansowanych
Warszawa - 2019-12-13
mgr Damian Kurpiewski
Image
Image
Objective-C dla programistów Swift
Jednodniowe szkolenie dla programistów Swift
Warszawa - 2019-10-26
dr Błażej Zyglarski
Image
Image
Programowanie funkcyjne i reaktywne w Swift
Dwudniowe szkolenie dla programistów Swift
Warszawa - 2019-11-30
mgr Damian Kurpiewski
Image
Image
Programowanie Gier 2D na iOS
Trzydniowe szkolenie ze SpriteKit i GameplayKit dla programistów Swift
Warszawa - 2019-11-08
dr Błażej Zyglarski