Składnia i semantyka są już dobrze zdefiniowane przez inne doskonałe odpowiedzi na to pytanie. Ponieważ wykonanie i wydajność nie są szczegółowo opisane, dodam swoją odpowiedź.
Jaka jest funkcjonalna różnica między tymi 3?
Zawsze uważałem atom za domyślny dość ciekawy. Na poziomie abstrakcji, nad którym pracujemy, wykorzystanie właściwości atomowych dla klasy jako pojazdu w celu osiągnięcia 100% bezpieczeństwa wątków jest bardzo ważne. W przypadku naprawdę poprawnych programów wielowątkowych interwencja programisty jest prawie na pewno wymogiem. Tymczasem charakterystyki wydajności i wykonanie nie zostały jeszcze szczegółowo opisane. Przez lata pisząc kilka programów wielowątkowych, nonatomic
cały czas deklarowałem swoje właściwości, ponieważ atom nie był sensowny w żadnym celu. Podczas dyskusji o szczegółach właściwości atomowych i nieatomowych to pytanie spowodowało, że pewne profilowanie napotkało ciekawe wyniki.
Wykonanie
Ok. Pierwszą rzeczą, którą chciałbym wyjaśnić, jest to, że implementacja blokująca jest zdefiniowana i abstrakcyjna. Louis używa @synchronized(self)
tego przykładu - widziałem to jako powszechne źródło zamieszania. Implementacja tak naprawdę nie korzysta @synchronized(self)
; używa blokad spinowych na poziomie obiektu . Ilustracja Louisa jest dobra na ilustrację wysokiego poziomu używającą konstruktów, które wszyscy znamy, ale ważne jest, aby wiedzieć, że nie używa @synchronized(self)
.
Kolejna różnica polega na tym, że właściwości atomowe będą zachowywać / zwalniać cykl obiektów w getterze.
Wydajność
Oto interesująca część: Wydajność wykorzystująca dostęp do właściwości atomowych w przypadkach bezspornych (np. Jednowątkowych) może być naprawdę bardzo szybka w niektórych przypadkach. W mniej niż idealnych przypadkach korzystanie z dostępu atomowego może kosztować ponad 20 razy więcej nonatomic
. Podczas gdy sporna sprawa wykorzystująca 7 wątków była 44 razy wolniejsza dla trzy-bajtowej struktury (2,2 GHz Core i7 Quad Core, x86_64). Trzy bajtowa struktura jest przykładem bardzo wolnej właściwości.
Interesująca uwaga dodatkowa: zdefiniowane przez użytkownika akcesoria trzy bajtowej struktury były 52 razy szybsze niż zsyntetyzowane akcesoria atomowe; lub 84% prędkości zsyntetyzowanych nieatomowych akcesoriów.
Przedmioty w spornych przypadkach mogą również przekroczyć 50 razy.
Ze względu na liczbę optymalizacji i odmian we wdrożeniach trudno jest zmierzyć rzeczywiste wpływy w tych kontekstach. Często możesz usłyszeć coś takiego: „Zaufaj, chyba że profilujesz i uważasz, że to problem”. Ze względu na poziom abstrakcji trudno jest zmierzyć rzeczywisty wpływ. Oczyszczanie rzeczywistych kosztów z profili może być bardzo czasochłonne, a ze względu na abstrakcje dość niedokładne. Również ARC vs MRC może mieć duże znaczenie.
Cofnijmy się więc, nie skupiając się na implementacji dostępu do nieruchomości, uwzględnimy zwykłych podejrzanych, takich jak objc_msgSend
, i zbadamy niektóre rzeczywiste wyniki wysokiego poziomu dla wielu wywołań NSString
gettera w przypadkach bezspornych (wartości w sekundach):
- MRC | nieatomowy | ręcznie zaimplementowane moduły pobierające: 2
- MRC | nieatomowy | syntezator getter: 7
- MRC | atomowy | syntezator getter: 47
- ARC | nieatomowy | syntezator getter: 38 (uwaga: dodawanie ARC do liczby cykli tutaj)
- ARC | atomowy | syntezator getter: 47
Jak zapewne się domyślacie, aktywność / cykl liczenia referencji ma znaczący wkład w atomikę i pod ARC. Widać też większe różnice w spornych sprawach.
Chociaż zwracam szczególną uwagę na wydajność, nadal mówię, że Semantics First! . Tymczasem wydajność ma niski priorytet w wielu projektach. Jednak znajomość szczegółów wykonania i kosztów używanych technologii z pewnością nie zaszkodzi. Powinieneś używać technologii odpowiedniej do swoich potrzeb, celów i umiejętności. Mamy nadzieję, że pozwoli to zaoszczędzić kilka godzin porównań i pomoże w podejmowaniu lepszych decyzji przy projektowaniu programów.