Od dawna używam DispatchQueue.main.async
do wykonywania operacji związanych z interfejsem użytkownika.
Swift zapewnia zarówno DispatchQueue.main.async
i DispatchQueue.main.sync
, jak i oba są wykonywane w głównej kolejce.
Czy ktoś może mi powiedzieć, jaka jest między nimi różnica? Kiedy powinienem używać każdego?
DispatchQueue.main.async {
self.imageView.image = imageView
self.lbltitle.text = ""
}
DispatchQueue.main.sync {
self.imageView.image = imageView
self.lbltitle.text = ""
}
źródło
DispatchQueue.main.sync
z wątku w tle?async
tam zadzwonili ? Chodzi mi o to, że skoro w wątku nie ma nic innego, to nie ma znaczenia. Gdyby tak było,DispatchQueue.main.sync {block1}; DispatchQueue.main.sync {block2};
to miałoby to sens. Ale kiedy nie ma innego bloku, nie mogę myśleć o korzyściach z używaniaDispatchQueue.main.sync {Oneblock}
goDispatchQueue.main.async {Oneblock}
. Dla obu z nich otrzymają priorytet / natychmiastowość mainQueue i nic im nie przeszkodzi.Dlaczego współbieżność?
Gdy tylko dodasz do aplikacji ciężkie zadania, takie jak ładowanie danych, spowalnia ona pracę interfejsu użytkownika lub nawet ją zawiesza. Współbieżność umożliwia wykonywanie 2 lub więcej zadań „jednocześnie”. Wadą tego podejścia jest bezpieczeństwo gwintów, które nie zawsze jest tak łatwe do kontrolowania. Na przykład, gdy różne zadania chcą uzyskać dostęp do tych samych zasobów, np. Próba zmiany tej samej zmiennej w różnych wątkach lub uzyskiwanie dostępu do zasobów już zablokowanych przez różne wątki.
Jest kilka abstrakcji, o których musimy wiedzieć.
Kolejki
Musi być seryjny lub równoległy . A także globalne lub prywatne w tym samym czasie.
W przypadku kolejek szeregowych zadania będą kończone pojedynczo, podczas gdy w przypadku kolejek współbieżnych zadania będą wykonywane jednocześnie i będą kończone zgodnie z nieoczekiwanymi harmonogramami. Ta sama grupa zadań zajmie znacznie więcej czasu w kolejce szeregowej w porównaniu z kolejką współbieżną.
Możesz tworzyć własne kolejki prywatne (zarówno szeregowe, jak i współbieżne ) lub korzystać z już dostępnych kolejek globalnych (systemowych) . Kolejka główny jest jedynym seryjnym kolejka z wszystkich globalnych kolejek .
Zdecydowanie zaleca się, aby nie wykonywać ciężkich zadań, które nie są związane z pracą interfejsu użytkownika w głównej kolejce (np. Ładowanie danych z sieci), ale zamiast tego wykonywać je w innych kolejkach, aby interfejs użytkownika nie był zamrażany i reagował na działania użytkownika. Jeśli pozwolimy zmienić interfejs użytkownika w innych kolejkach, zmiany mogą zostać wprowadzone w innym i nieoczekiwanym harmonogramie i szybkości. Niektóre elementy interfejsu użytkownika można narysować przed lub po ich pojawieniu się. Może to spowodować awarię interfejsu użytkownika. Musimy również pamiętać, że skoro kolejki globalne są kolejkami systemowymi, system może na nich wykonywać inne zadania.
Jakość usług / priorytet
Kolejki mają również różne qos (Quality of Service), które ustawiają priorytet zadania (od najwyższego do najniższego):
.userInteractive - kolejka główna
.userInitiated - dla zadań inicjowanych przez użytkownika, na które użytkownik czeka na odpowiedź.
Użyteczność - dla zadań co zajmuje trochę czasu i nie wymaga natychmiastowej reakcji, np. praca z danymi
.background - dla zadań niezwiązanych z częścią wizualną, które nie są ściśle związane z czasem realizacji).
Istnieje również kolejka
.default, która nie przenosi informacji qos . Jeśli nie można było wykryć qos, toqos będzie używany między .userInitiated i .utility .
Zadania można wykonywać synchronicznie lub asynchronicznie .
Funkcja synchroniczna przywraca sterowanie do bieżącej kolejki dopiero po zakończeniu zadania. Blokuje kolejkę i czeka na zakończenie zadania.
Funkcja asynchroniczna zwraca sterowanie do bieżącej kolejki zaraz po wysłaniu zadania do wykonania w innej kolejce. Nie czeka na zakończenie zadania. Nie blokuje kolejki.
Typowe problemy.
Oto najpopularniejsze błędy popełniane przez programistów podczas projektowania aplikacji współbieżnych:
NIGDY nie wywołuj funkcji synchronizacji w głównej kolejce .
Jeśli wywołasz funkcję synchronizacji w głównej kolejce, zablokuje ona kolejkę, a kolejka będzie czekała na zakończenie zadania, ale zadanie nigdy nie zostanie ukończone, ponieważ nie będzie można go nawet uruchomić, ponieważ kolejka jest już zablokowane. Nazywa się to impasem .
Kiedy używać synchronizacji? Kiedy musimy poczekać, aż zadanie zostanie zakończone. Fe, gdy upewniamy się, że jakaś funkcja / metoda nie jest wywoływana podwójnie. Mamy synchronizację i próbujemy zapobiec podwójnemu wywołaniu, dopóki nie zostanie całkowicie zakończona. Oto kod dotyczący tego problemu:
Jak dowiedzieć się, co spowodowało raport o awarii urządzenia z systemem IOS?
źródło
DispatchQueue.main.sync
z wątku w tle?GCD
umożliwia wykonanie zadaniasynchronously
lubasynchronously
[Informacje]synchronous
(blokuj i czekaj) zwraca kontrolę, kiedy zadanie zostanie zakończoneasynchronous
Funkcja (wysyłka i kontynuacja) natychmiast zwraca formant, wysyłając zadanie do uruchomienia do odpowiedniej kolejki, ale nie czekając na jego zakończenie.[DispatchQueue]
źródło
sync
lubasync
metody nie mają wpływu na kolejkę, w której są wywoływane.sync
zablokuje wątek, z którego jest wywoływany, a nie kolejkę, w której jest wywoływany. Jest to właściwość,DispatchQueue
która decyduje o tym, czyDispatchQueue
będzie czekał na wykonanie zadania (kolejka szeregowa), czy może uruchomić kolejne zadanie przed zakończeniem bieżącego zadania (kolejka współbieżna).Więc nawet jeśli
DispatchQueue.main.async
jest to wywołanie asynchroniczne, dodana do niego ciężka operacja może spowodować zawieszenie interfejsu użytkownika, ponieważ jej operacje są wykonywane szeregowo w głównym wątku. Jeśli ta metoda jest wywoływana z wątku w tle, sterowanie wróci do tego wątku natychmiastowo, nawet jeśli interfejs użytkownika wydaje się być zablokowany. Dzieje się tak, ponieważasync
nawiązywane jest połączenieDispatchQueue.main
źródło