Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Parallele Programmierung (DE)

Parallele Programmierung (DE)

Bei CocoaHeads Dresden

Ade0c334ecff1448bb96f5f733bf1f83?s=128

Chris Eidhof | @chriseidhof

September 11, 2013
Tweet

Transcript

  1. Parallele Programmierung Chris Eidhof Sunday, September 22, 13

  2. Achtung Sunday, September 22, 13

  3. Nicht alles muss async sein • Schwer zu debuggen •

    Schwer zu lesen und schreiben • Fehleranfällig Sunday, September 22, 13
  4. APIs • OpenCL • pthread • NSRunLoop • NSThread •

    Grand Central Dispatch • Operation Queues Sunday, September 22, 13
  5. pthread size_t count; }; struct threadResult { uint32_t min; uint32_t

    max; }; void * findMinAndMax(void *arg) { struct threadInfo const * const info = (struct threadInfo *) arg; uint32_t min = UINT32_MAX; uint32_t max = 0; for (size_t i = 0; i < info->count; ++i) { uint32_t v = info->inputValues[i]; min = MIN(min, v); max = MAX(max, v); } free(arg); struct threadResult * const result = (struct threadResult *) malloc(sizeof(*result)); result->min = min; result->max = max; return result; } int main(int argc, const char * argv[]) { size_t const count = 1000000; uint32_t inputValues[count]; // Fill input values with random numbers: for (size_t i = 0; i < count; ++i) { inputValues[i] = arc4random(); } // Spawn 4 threads to find the minimum and maximum: size_t const threadCount = 4; pthread_t tid[threadCount]; for (size_t i = 0; i < threadCount; ++i) { struct threadInfo * const info = (struct threadInfo *) malloc(sizeof(*info)); size_t offset = (count / threadCount) * i; info->inputValues = inputValues + offset; info->count = MIN(count - offset, count / threadCount); int err = pthread_create(tid + i, NULL, &findMinAndMax, info); NSCAssert(err == 0, @"pthread_create() failed: %d", err); } // Wait for the threads to exit: struct threadResult * results[threadCount]; for (size_t i = 0; i < threadCount; ++i) { int err = pthread_join(tid[i], (void **) &(results[i])); NSCAssert(err == 0, @"pthread_join() failed: %d", err); } // Find the min and max: uint32_t min = UINT32_MAX; uint32_t max = 0; for (size_t i = 0; i < threadCount; ++i) { Sunday, September 22, 13
  6. NSRunloop [self performSelector:@selector(mySelector:) withObject:nil afterDelay:1.0]; Sunday, September 22, 13

  7. @interface FindMinMaxThread : NSThread @property (nonatomic) NSUInteger min; @property (nonatomic)

    NSUInteger max; - (instancetype)initWithNumbers:(NSArray *)numbers; @end @implementation FindMinMaxThread { NSArray *_numbers; } - (instancetype)initWithNumbers:(NSArray *)numbers { self = [super init]; if (self) { _numbers = numbers; } return self; } - (void)main { NSUInteger min; NSUInteger max; // process the data self.min = min; self.max = max; } @end NSSet *threads = [NSMutableSet set]; NSUInteger numberCount = self.numbers.count; NSUInteger threadCount = 4; for (NSUInteger i = 0; i < threadCount; i++) { NSUInteger offset = (count / threadCount) * i; NSUInteger count = MIN(numberCount - offset, numberCount / threadCount); NSRange range = NSMakeRange(offset, count); NSArray *subset = [self.numbers subarrayWithRange:range]; FindMinMaxThread *thread = [[FindMinMaxThread alloc] initWithNumbers:subset]; [threads addObject:thread]; [thread start]; } NSThread Sunday, September 22, 13
  8. Wie viele Threads brauchen wir? Sunday, September 22, 13

  9. Grand Central Dispatch Sunday, September 22, 13

  10. Sunday, September 22, 13

  11. Sunday, September 22, 13

  12. Sunday, September 22, 13

  13. Parallel Seriell Sunday, September 22, 13

  14. Prioritätsinversion R N H M Sunday, September 22, 13

  15. Async Blocks dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(defaultQueue, ^{ [self

    expensiveBackgroundCode]; }); Sunday, September 22, 13
  16. UI Aktualisieren dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(defaultQueue, ^{ [self

    expensiveBackgroundCode]; dispatch_async(dispatch_get_main_queue(), ^{ self.label.text = @"Done"; }); }); Sunday, September 22, 13
  17. Mein Code: dispatch_async(backgroundQueue, ^{ NSData* contents = [NSData dataWithContentsOfURL:url]; dispatch_async(dispatch_get_main_queue(),

    ^{ // do something with the data. }); }); Sunday, September 22, 13
  18. Probleme • Nicht abbrechbar • Blockierend Sunday, September 22, 13

  19. NSOperationQueue NSOperationQueue* backgroundQueue; [backgroundQueue addOperation:downloadOperation]; Sunday, September 22, 13

  20. Abbrechen [downloadOperation cancel]; Sunday, September 22, 13

  21. Blocks [backgroundQueue addOperationWithBlock:^{ [self expensiveOperation]; }]; Sunday, September 22, 13

  22. Eigene Operations @interface DownloadOperation : NSOperation @end Sunday, September 22,

    13
  23. Weitere Aspekte • Abhängigkeiten • maxConcurrentOperationCount • Auf Grand Central

    Dispatch basiert Sunday, September 22, 13
  24. Unterklassen • NSInvocationOperation • NSBlockOperation Sunday, September 22, 13

  25. Async Core Data Am einfachsten: über den Haupt-Thread Sunday, September

    22, 13
  26. NSManagedObjectContext* context = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateQueueConcurrencyType]; context.persistentStoreCoordinator = self.persistentStoreCoordinator;

    Sunday, September 22, 13
  27. [context performBlock:^{ [self expensiveImportOperation]; }]; Sunday, September 22, 13

  28. Main context aktualisieren [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:nil usingBlock:^(NSNotification* note)

    { NSManagedObjectContext *moc = mainManagedObjectContext; if (note.object != moc) { [moc performBlock:^(){ [moc mergeChangesFromContextDidSaveNotification:note]; }]; } }]; Sunday, September 22, 13
  29. Es gibt noch immer ein Lock Du kannst aber zwei

    Persistent Store Coordinators verwenden Sunday, September 22, 13
  30. UI im Hintergrund [operationQueue addOperationWithBlock:^{ NSNumber* result = findLargestMersennePrime(); [[NSOperationQueue

    mainQueue] addOperationWithBlock:^{ self.textLabel.text = [result stringValue]; }]; }]; Sunday, September 22, 13
  31. UIKit ist nicht Threadsicher Sunday, September 22, 13

  32. Parallel zeichnen UIGraphicsBeginImageContextWithOptions(size, NO, 0); // drawing code here UIImage

    *i = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return i; Sunday, September 22, 13
  33. Parallel zeichnen • Nur wenn es notwendig ist • Vielleicht

    kannst du es vermeiden • WWDC 2012 - Building Concurrent User Interfaces on iOS Sunday, September 22, 13
  34. More reading • http://www.objc.io/issue-2 • Concurrency Programming Guide Sunday, September

    22, 13
  35. Kontakt @chriseidhof http://www.objc.io http://www.uikonf.com http://chris.eidhof.nl Sunday, September 22, 13