2011-07-24 24 views
13

Od czasu do czasu zauważam, że używam bloku do iteracji nad kolekcją bez zapisywania do współdzielonych danych lub wywoływania jakichkolwiek skutków ubocznych. Zastanawiam się nad dodaniem opcji NSEnumerationConcurrent, a następnie odrzuć ją, ponieważ nie rozumiem, kiedy warto jej użyć.Kiedy używać NSEnumerationConcurrent

Mam więc konkretne pytanie i bardziej ogólne.

Pierwsze pytanie: Oto może nieznacznie wymyślony przykład użycia bloku zrobić coś trywialnego dwutorowo:

CGFloat GetAverageHeight(NSArray* people) 
{ 
    NSUInteger count = [people count]; 
    CGFloat* heights = malloc(sizeof(CGFloat) * count); 

    [people enumerateObjectsWithOptions: NSEnumerationConcurrent usingBlock: 
    ^(id person, NSUInteger idx, BOOL* stop) 
    { 
    heights[idx] = [person height]; 
    }]; 

    CGFloat total= 0.0; 
    for (size_t i = 0 ; i < count ; i++) total += heights[i]; 
    free(heights); 
    return total/count; 
} 

ignorując fakt, że zakaz równoczesnego wyliczenie mogło tylko podsumować wysokość bezpośrednio, bez konieczności za wywołanie funkcji malloc lub drugiej połowy funkcji, czy jest jakiś punkt używający tutaj NSEnumerationConcurrent? Czy obciążenie związane z używaniem GCD (lub cokolwiek NSEnumerationConcurrent nie działa w tle) neguje zysk jednoczesnego uzyskiwania banalnej własności? O ile mniej trywialna musi być praca bloku, zanim warto skorzystać z NSEnumerationConcurrent?

Drugie pytanie: Bardziej ogólnie, czy powinienem uważać współbieżność za coś, co powinienem wykorzystać, gdy widzę taką możliwość (rationale: przypuszczalnie punktem tych API jest to, że współdziałają mniej ze specjalnym przypadkiem i większą częścią ogólnego wyglądu programu), lub tylko optymalizacji, której powinienem użyć tylko wtedy, gdy znalazłem konkretny problem z wydajnością i wierzę, że współbieżność jest odpowiedzią (racjonalne: błędy w kodzie współbieżnym są koszmarem do wyśledzenia)?

Odpowiedz

10

Generalnie używałbyś tylko współbieżności, gdy operacje do wykonania są stosunkowo "ciężkie". Nawet wtedy użycie surowej współbieżności oferowanej przez enumerateObjectsWithOptions: może być problematyczne, jeśli równoległość jest niewłaściwą ziarnistością dla danego zadania.

GCD jest naprawdę cholernie skuteczny w podkręcaniu i przetwarzaniu rzeczy, ale ten kod najprawdopodobniej zakończy się wywołaniem malloc() w celu skopiowania bloku (w zależności od tego, czy blok ma unikalny przechwycony stan).

Odpowiedź na drugie pytanie wypełnia wiele książek, najbardziej bezużyteczne.

Przyjmowanie kodu niezgodnego i jednoczesnego jest ogólnie bardzo trudnym problemem z koszmarnymi błędami. Projektowanie z wyprzedzeniem może być jednak wyjątkowo czasochłonne. Co gorsza, implementacja dla przyszłej współbieżności bez faktycznego używania go prowadzi do koszmarnego doświadczenia podczas włączania.

Jeden kluczowy punkt; rozważając współbieżność, skoncentruj się na tworzeniu całych podprogramów pojedynczych wątków z wyjątkiem wyjątkowo dobrze zdefiniowanego granicznego interfejsu API obejmującego wątki/kolejki. Dobrym tego przykładem są Core Data.

Powiązane problemy