2013-04-29 20 views
200

Mam pytanie wokół tego koduZrozumienie dispatch_async

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 ten kod jest

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

Czy jesteśmy pytając ten kod do wykonywania zadań szeregowe na globalnej kolejce którego sama definicja jest taka, że ​​to zwraca globalną kolejkę współbieżną o danym priorytecie?

Co jest zaletą korzystania z dispatch_get_global_queue w głównej kolejce?

Jestem zdezorientowany. Czy mógłbyś mi pomóc lepiej to zrozumieć?

+1

Powinieneś lepiej wyciąć swój kod w kilku liniach, więc jej co więcej sensu. zabezpiecz swoją 'dispatch_get_global_queue' wewnątrz typu zmiennej' dispatch_queue_t myQueue'. Bardziej czytelne przekazywanie tylko ** myQueue ** do twojego '' dispatch_async' –

Odpowiedz

462

Głównym powodem, dla którego używa się domyślnej kolejki nad główną kolejką, jest uruchamianie zadań w tle.

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

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ 
    //Background Thread 
    dispatch_async(dispatch_get_main_queue(), ^(void){ 
     //Run UI Updates 
    }); 
}); 
+0

Rozumiem, że David dziękuje za odpowiedź, ale moje pytanie było bardziej zrozumiałe, logika robienia tego, tj. Prosiła ten kod o wykonywanie zadań szeregowych w globalnej kolejce która jest równoległa kolejką sama w sobie – user2332873

+0

Robię dokładnie to, co sugerujesz, ale jakoś, uiTableViewCell nie aktualizuje od razu, gdy wywołuję [self.tableView reloadData] w Aktualizacji UI Run.To trwa około 4 lub 5 sekund. wariuję od kilku dni – GrandSteph

+0

@GrandSteph Nie jestem zbyt zaznajomiony z tą metodą.Może ta metoda zajmuje tylko 5 sekund.Główną rzeczą w dispatch_async jest to, że pozwala ci robić rzeczy w tle bez zawieszania głównego – David

183

Wszystkie kolejek DISPATCH_QUEUE_PRIORITY_X są kolejki jednoczesnych (czyli mogą wykonywać wiele zadań na raz) i są FIFO w tym sensie, że zadania w danej kolejce rozpocznie wykonywanie za pomocą „pierwsze weszło, pierwsze wyszło” porządek . Jest to w porównaniu do głównej kolejki (z dispatch_get_main_queue()), która jest kolejką szeregową (zadania zaczną się wykonywać i kończą wykonywanie 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, te zadania zaczną być wykonywane w kolejności wysłania ich do kolejki. Podobnie dla kolejek WYSOKI, NISKI i TŁO. Wszystko, co wysyłasz do którejkolwiek z tych kolejek, jest wykonywane w tle na 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, obliczanie itp.

Należy zauważyć, że kolejność wykonywania jest równa FIFO dla każdej kolejki. Więc jeśli wyślesz 1000 zadań dispatch_async() do czterech różnych równoległych kolejek, równo dzieląc je i wysyłając je na BACKGROUND, LOW, DEFAULT i HIGH w kolejności (tj. Zaplanujesz ostatnie 250 zadań w kolejce HIGH), jest bardzo prawdopodobne, że pierwsze zadania, które widzisz zaczynasz, będą dotyczyły tej kolejki WYSOKIEJ, ponieważ system podjął Twoją sugestię, że te zadania muszą dostać się do procesora tak szybko, jak to możliwe.

Należy również zauważyć, że mówię "zacznę wykonywać w kolejności", ale należy pamiętać, że jako współbieżne kolejki rzeczy niekoniecznie będą KONIECZNE, wykonywane w kolejności w zależności od długości czasu dla każdego zadania.

Zgodnie Apple:

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

współbieżne kolejka w sklepie jest przydatna, gdy masz wiele zadań, które mogą być stosowane równolegle. Kolejka współbieżna wciąż jest kolejką, w której zapisuje kolejność zadań w kolejności od pierwszego do drugiego; jednak kolejka współbieżna może anulować dodatkowe zadania przed zakończeniem poprzednich zadań. Rzeczywista liczba zadań wykonywanych przez kolejkę współbieżną w danym momencie jest zmienna i może zmieniać się dynamicznie wraz ze zmianą warunków w aplikacji. Na liczbę zadań wykonywanych przez kolejki współbieżne wpływa wiele czynników, w tym liczba dostępnych rdzeni, ilość pracy wykonywanej przez inne procesy oraz liczba i priorytet zadań w innych kolejkach wysyłania szeregowego.

Zasadniczo, jeśli wyślesz te 1000 dispatch_async() Bloki do domyślnej, wysokie, niskie lub kolejki TLE będą wszystko zacząć realizować w kolejności ich wysyłania. Krótsze zadania mogą się jednak zakończyć przed dłuższymi. Powody tego są następujące: jeśli dostępne są rdzenie procesorów lub bieżące zadania kolejki wykonują obliczeniowo nieintensywną pracę (co powoduje, że system myśli, że może równolegle wysyłać dodatkowe zadania, niezależnie od liczby rdzeni).

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

Aby odpowiedzieć na powyższe pytanie: jesteś częściowo poprawny. "Pytasz ten kod", aby wykonywać równoczesne zadania 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 systemu.

"Kolejka" główna z drugiej strony (z dispatch_get_main_queue()) jest kolejką szeregową (nie współbieżną). Zadania wysyłane do głównej kolejki będą zawsze wykonywane w kolejności i będą zawsze kończyć się w kolejności. Zadania te będą również wykonywane na UI wątek dlatego nadaje się do aktualizowania UI z komunikatów postępu, powiadomień o zakończeniu operacji, itp

+0

+1, ale myślę, że w praktyce nie ma znaczenia, czy kolejki równoległe są FIFO czy po prostu kolejność losowa. Jeśli rozpoczniesz 5 zadań w pętli, załóżmy, że zasadniczo zaczną się w tym samym czasie. Nie ma gwarancji, że np. pierwsza operacja I/O pierwszego zadania nastąpi przed piątym, nawet jeśli wykonają ten sam kod. OTOH, dla kolejek szeregowych, zachowanie FIFO jest niezbędne, a IMHO jest to definiująca różnica między dwoma typami kolejek. –

+0

Wyjaśnienie Incredile. Bardzo dużo klaszcze! –

23

wersji Swift

To jest wersja Swift Objective-C odpowiedź Dawida. Używanie globalnej kolejki do uruchamiania zadań w tle i głównej kolejki w celu aktualizacji interfejsu użytkownika.

Swift 3

DispatchQueue.global(qos: .background).async { 

    // Background Thread 

    DispatchQueue.main.async { 
     // Run UI Updates 
    } 
}