Zrozumienie dispatch_async

233

Mam pytanie dotyczące tego kodu

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData* data = [NSData dataWithContentsOfURL: 
      kLatestKivaLoansURL];
    [self performSelectorOnMainThread:@selector(fetchedData:) 
      withObject:data waitUntilDone:YES];
});

Pierwszy parametr tego kodu to

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

Czy pytamy ten kod o wykonywanie zadań szeregowych w globalnej kolejce, której sama definicja polega na tym, że zwraca globalną kolejkę współbieżną o danym poziomie priorytetu?

Jaka jest zaleta korzystania dispatch_get_global_queuez głównej kolejki?

Jestem zdezorientowany. Czy możesz mi pomóc lepiej to zrozumieć.

użytkownik2332873
źródło
1
Lepiej wytnij kod w kilka wierszy, aby miało to większy sens. zabezpieczyć dispatch_get_global_queuewnętrze różnego rodzaju dispatch_queue_t myQueue. Bardziej czytelne jest przekazywanie tylko myQueue do twojego `` dispatch_async``
Alex Cio

Odpowiedzi:

517

Głównym powodem używania kolejki domyślnej w kolejce głównej jest uruchamianie zadań w tle.

Na przykład, jeśli pobieram plik z Internetu i chcę zaktualizować użytkownika o postępie pobierania, uruchomię pobieranie w domyślnej kolejce priorytetowej i asynchronicznie zaktualizuję interfejs użytkownika w głównej kolejce.

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //Run UI Updates
    });
});
David
źródło
Rozumiem, że David podziękował za twoją odpowiedź, ale moje pytanie dotyczyło bardziej logiki zrobienia tego, tj.
Poproszenia
Robię dokładnie to, co sugerujesz, ale jakoś uiTableViewCell nie aktualizuje od razu, kiedy wywołuję [self.tableView reloadData] w Aktualizacjach UI. Zajmuje to około 4-5 sekund. Doprowadza mnie to do szału od kilku dni .
GrandSteph
@GrandSteph Nie znam tej metody zbyt dobrze. Być może uruchomienie tej metody zajmuje tylko 5 sekund. Ważną rzeczą w dispatch_async jest to, że pozwala robić rzeczy w tle bez zawieszania głównego wątku.
David
2
co 0oznacza
Honey,
3
@ Kochanie 0 to flagsparametr, który obecnie nie robi absolutnie nic. Z dokumentów:Flags that are reserved for future use. Always specify 0 for this parameter.
David
199

Wszystkie kolejki DISPATCH_QUEUE_PRIORITY_X są kolejkami równoczesnymi (co oznacza, że ​​mogą wykonywać wiele zadań jednocześnie) i są FIFO w tym sensie, że zadania w danej kolejce zaczną być wykonywane w kolejności „pierwsze przyszło, pierwsze wyszło”. Jest to w porównaniu z kolejką główną (z dispatch_get_main_queue ()), która jest kolejką szeregową (zadania zaczną się kończyć i kończą się w kolejności, w jakiej zostały odebrane).

Tak więc, jeśli wyślesz 1000 bloków dispatch_async () do DISPATCH_QUEUE_PRIORITY_DEFAULT, zadania te zaczną być wykonywane w kolejności, w jakiej je wysłałeś do kolejki. Podobnie w przypadku kolejek WYSOKIE, NISKIE i TŁO. Wszystko, co wysyłasz do którejkolwiek z tych kolejek, jest wykonywane w tle w alternatywnych wątkach, z dala od głównego wątku aplikacji. Dlatego te kolejki są odpowiednie do wykonywania zadań, takich jak pobieranie w tle, kompresja, obliczenia itp.

Należy pamiętać, że kolejność wykonywania jest FIFO na podstawie kolejki. Jeśli więc wyślesz 1000 zadań dispatch_async () do czterech różnych równoczesnych kolejek, równomiernie je dzieląc i wysyłając do BACKGROUND, LOW, DEFAULT i HIGH w kolejności (tj. Planujesz ostatnie 250 zadań w kolejce HIGH), jest bardzo prawdopodobne, że pierwsze zadania, które zaczniesz, będą w tej kolejce WYSOKIEJ, ponieważ system przyjął twoją sugestię, że zadania te muszą dotrzeć do procesora tak szybko, jak to możliwe.

Zauważ też, że mówię „zacznie wykonywać w kolejności”, ale pamiętaj, że w przypadku równoczesnych kolejek rzeczy niekoniecznie kończą wykonywanie w kolejności, w zależności od długości czasu dla każdego zadania.

Zgodnie z Apple:

https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

Współbieżna kolejka wysyłkowa jest przydatna, gdy masz wiele zadań, które można uruchamiać równolegle. Współbieżna kolejka jest nadal kolejką, ponieważ usuwa kolejność zadań w kolejności „pierwsze przyszło, pierwsze wyszło”; jednak współbieżna kolejka może anulować kolejność zadań dodatkowych przed zakończeniem jakichkolwiek poprzednich zadań. Rzeczywista liczba zadań wykonywanych przez współbieżną kolejkę w danym momencie jest zmienna i może zmieniać się dynamicznie wraz ze zmianami warunków w aplikacji. Wiele czynników wpływa na liczbę zadań wykonywanych przez współbieżne kolejki, w tym liczbę dostępnych rdzeni, ilość pracy wykonanej przez inne procesy oraz liczbę i priorytet zadań w innych kolejkach wysyłki szeregowej.

Zasadniczo, jeśli wyślesz te 1000 bloków dispatch_async () do kolejki DEFAULT, HIGH, LOW lub BACKGROUND, wszystkie zaczną działać w kolejności, w jakiej je wysyłasz. Jednak krótsze zadania mogą zakończyć się przed dłuższymi. Powodem tego są dostępne rdzenie procesora lub bieżące zadania w kolejce wykonują obliczeniowo niewymagające intensywności prace (co sprawia, że ​​system myśli, że może równolegle wykonywać dodatkowe zadania niezależnie od liczby rdzeni).

Poziom współbieżności jest w całości obsługiwany przez system i jest oparty na obciążeniu systemu i innych wewnętrznych czynnikach. To jest piękno Grand Central Dispatch (system dispatch_async ()) - po prostu tworzysz swoje jednostki robocze jako bloki kodu, ustawiasz dla nich priorytet (na podstawie wybranej przez ciebie kolejki) i pozwalasz systemowi zająć się resztą.

Tak więc, aby odpowiedzieć na powyższe pytanie: masz częściowo rację. „Pytasz ten kod” o wykonywanie równoczesnych zadań w globalnej kolejce współbieżnej na określonym poziomie priorytetu. Kod w bloku będzie wykonywany w tle, a każdy dodatkowy (podobny) kod będzie wykonywany potencjalnie równolegle, w zależności od oceny dostępnych zasobów przez system.

Z kolei „główna” kolejka (z dispatch_get_main_queue ()) jest kolejką szeregową (nie współbieżną). Zadania wysyłane do kolejki głównej będą zawsze wykonywane w kolejności i zawsze kończą się w kolejności. Te zadania będą również wykonywane w wątku interfejsu użytkownika, więc nadaje się do aktualizowania interfejsu użytkownika za pomocą komunikatów o postępach, powiadomień o zakończeniu itp.

SimplePanda
źródło
+1, ale myślę, że w praktyce nie ma większego znaczenia, czy współbieżne kolejki to FIFO, czy tylko kolejność losowa. Jeśli rozpoczniesz 5 zadań w pętli, załóż, że w zasadzie zaczną się w tym samym czasie. Nie ma gwarancji, że np. Pierwsza operacja we / wy pierwszego zadania nastąpi przed piątym, nawet jeśli wykonają ten sam kod. OTOH, w przypadku kolejek szeregowych kluczowe znaczenie ma zachowanie FIFO, a IMHO to różnica definiująca oba typy kolejek.
Gerhard Wesp,
Niesamowite wyjaśnienie. Dużo klaszcze!
Okhan Okbay
36

Wersja szybka

To jest szybka wersja odpowiedzi Objective-C Davida. Za pomocą globalnej kolejki można uruchamiać rzeczy w tle, a kolejki głównej aktualizować interfejs użytkownika.

DispatchQueue.global(qos: .background).async {
    
    // Background Thread
    
    DispatchQueue.main.async {
        // Run UI Updates
    }
}
Suragch
źródło