Skip to content

Instantly share code, notes, and snippets.

@alloy
Forked from kastiglione/gcd_map.mm
Created May 31, 2013 17:31
Show Gist options
  • Save alloy/5686542 to your computer and use it in GitHub Desktop.
Save alloy/5686542 to your computer and use it in GitHub Desktop.
#import <Foundation/Foundation.h>
#import <libkern/OSAtomic.h>
@interface NSArray (ConcurrentMap)
- (NSArray*)semaphore_map:(id (^)(id))block;
- (NSArray*)serial_map:(id (^)(id))block;
- (NSArray*)spinlock_map:(id (^)(id))block;
- (NSArray*)direct_map:(id (^)(id))block;
@end
@implementation NSArray (ConcurrentMap)
- (NSArray*)semaphore_map:(id (^)(id))block {
__strong id* collected = (__strong id*)calloc(self.count, sizeof(id));
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_apply(self.count, queue, ^(size_t i) {
id result = block(self[i]);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
collected[i] = result;
dispatch_semaphore_signal(semaphore);
});
NSArray* result = [NSArray arrayWithObjects:collected count:self.count];
free(collected);
return result;
}
- (NSArray*)serial_map:(id (^)(id))block {
__strong id* collected = (__strong id*)calloc(self.count, sizeof(id));
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_queue_t serial = dispatch_queue_create("com.internet", DISPATCH_QUEUE_SERIAL);
dispatch_apply(self.count, queue, ^(size_t i) {
id result = block(self[i]);
dispatch_group_async(group, serial, ^{
collected[i] = result;
});
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSArray* result = [NSArray arrayWithObjects:collected count:self.count];
free(collected);
return result;
}
- (NSArray*)spinlock_map:(id (^)(id))block {
__strong id* collected = (__strong id*)calloc(self.count, sizeof(id));
__block volatile OSSpinLock spinLock = OS_SPINLOCK_INIT;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_apply(self.count, queue, ^(size_t i) {
id result = block(self[i]);
OSSpinLockLock(&spinLock);
collected[i] = result;
OSSpinLockUnlock(&spinLock);
});
NSArray* result = [NSArray arrayWithObjects:collected count:self.count];
free(collected);
return result;
}
- (NSArray*)direct_map:(id (^)(id))block {
__strong id* collected = (__strong id*)calloc(self.count, sizeof(id));
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_apply(self.count, queue, ^(size_t i) {
collected[i] = block(self[i]);
});
NSArray* result = [NSArray arrayWithObjects:collected count:self.count];
free(collected);
return result;
}
@end
int main(int argc, const char* argv[]) {
@autoreleasepool {
NSUInteger const ARRAY_SIZE = 1000;
NSUInteger const LOOP_COUNT = 20000;
NSMutableArray* numbers = [NSMutableArray arrayWithCapacity:ARRAY_SIZE];
for (NSUInteger i = 0; i < ARRAY_SIZE; i++) {
[numbers addObject:@(i)];
}
NSDate* start;
@autoreleasepool {
start = [NSDate date];
for (NSUInteger i = 0; i < LOOP_COUNT; i++) {
[numbers serial_map:^(id value) {
return value;
}];
}
NSLog(@"serial_map: %.2fs", -[start timeIntervalSinceNow]);
}
@autoreleasepool {
start = [NSDate date];
for (NSUInteger i = 0; i < LOOP_COUNT; i++) {
[numbers semaphore_map:^(id value) {
return value;
}];
}
NSLog(@"semaphore_map: %.2fs", -[start timeIntervalSinceNow]);
}
@autoreleasepool {
start = [NSDate date];
for (NSUInteger i = 0; i < LOOP_COUNT; i++) {
[numbers spinlock_map:^(id value) {
return value;
}];
}
NSLog(@"spinlock_map: %.2fs", -[start timeIntervalSinceNow]);
}
@autoreleasepool {
start = [NSDate date];
for (NSUInteger i = 0; i < LOOP_COUNT; i++) {
[numbers direct_map:^(id value) {
return value;
}];
}
NSLog(@"direct_map: %.2fs", -[start timeIntervalSinceNow]);
}
}
return 0;
}
2013-05-31 19:29:25.237 a.out[34425:707] serial_map: 8.96s
2013-05-31 19:29:35.908 a.out[34425:707] semaphore_map: 10.45s
2013-05-31 19:29:39.329 a.out[34425:707] spinlock_map: 3.20s
2013-05-31 19:29:40.837 a.out[34425:707] direct_map: 1.30s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment