2011-07-24 13 views
13

Ogni tanto, noto che sto utilizzando un blocco per scorrere su una raccolta senza scrivere alcun dato condiviso o causare effetti collaterali. Considero l'aggiunta di un'opzione NSEnumerationConcurrent, quindi decido in quanto non capisco davvero quando valga la pena utilizzarla.Quando utilizzare NSEnumerationConcurrent

Quindi ho una domanda specifica e una più generale.

Prima domanda: Ecco un esempio forse un po 'artificiosa di utilizzare un blocco di fare qualcosa di banale in concomitanza:

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; 
} 

Ignorando il fatto che un'enumerazione non concorrente potrebbe avere appena riassunto l'altezza direttamente, senza la necessità per chiamare malloc o la seconda metà della funzione, c'è qualche punto che usa NSEnumerationConcurrent qui? Il sovraccarico dell'utilizzo di GCD (o di qualsiasi altro NSEnumerationConcurrent in background) annulla il guadagno di ottenere una proprietà banale contemporaneamente? Quanto meno banale deve fare il lavoro del blocco prima che valga la pena utilizzare NSEnumerationConcurrent?

Seconda domanda: Più in generale, dovrei considerare la concorrenza come qualcosa che dovrei usare quando vedo un'opportunità per farlo (razionale: presumibilmente il punto di queste API è che rendono la concorrenza meno di un caso speciale e più parte del trucco generale di un programma), o solo un'ottimizzazione che dovrei usare solo se ho trovato un problema di prestazioni specifico e credo che la concorrenza sia la risposta (logica: i bug nel codice concorrente sono un incubo da rintracciare)?

risposta

10

In genere si utilizza la concorrenza solo quando le operazioni da eseguire sono relativamente "pesanti". Anche in questo caso, l'utilizzo della concorrenza non elaborata offerta da enumerateObjectsWithOptions: potrebbe facilmente essere problematico se il parallelismo è la granularità errata per l'attività in corso.

GCD è davvero dannatamente efficiente nell'accodamento e nell'elaborazione di materiale, ma è probabile che il codice finisca per chiamare malloc() per copiare il blocco (dipende dal fatto che il blocco abbia uno stato acquisito univoco).

La risposta alla tua seconda domanda riempie molti libri, in gran parte inutili.

Prendere un codice non simultaneo e renderlo concorrente è generalmente un Problema Molto Difficile pieno di bug da incubo. Tuttavia, progettare in anticipo la concorrenza può richiedere molto tempo. Peggio ancora, implementare per una concorrenza futura senza usarla in realtà porta solo a un'esperienza di debug da incubo quando lo si accende.

Un punto chiave; quando si considera la concorrenza, concentrarsi sulla creazione di interi sotto-grafici di oggetti isolati dal thread, salvo per un'API limite eccessivamente ben definita che si estende su thread/code. Un buon esempio di questo è Core Data.