Concurrent Programming 的 API

Concurrent Programming: APIs and Challenges - objc.io issue #2 的整理筆記

難 -> 易 : pthread、NSThread、GCD、NSOperationQueue

使用 GCD

預設有五個 queue

  1. main queue
  2. 3 個不同 priority queue
  3. I/O queue

大多數情況使用 default 的 priority queue 就好,避免 priority inversion

使用 Operation Queues

可透過 override main or start 定義自己的 operations。

重寫 main 的方式當 return 時,這 operation 就結束了

@implementation YourOperation
- (void)main
{
// 進行處理 ...
}
@end

更多處理或者要可以 async,這情況下需要手動管理狀態,使用預設的 setter 才會發送 KVO,否則需要自己發送。

@implementation YourOperation
- (void)start
{
self.isExecuting = YES;
self.isFinished = NO;
// 開始處理,在結束時應該調用 finished ...
}

- (void)finished
{
self.isExecuting = NO;
self.isFinished = YES;
}
@end

為了使用 cancel,需一直檢查 isCancelled 屬性。

- (void)main
{
while (notDone && !self.isCancelled) {
// 進行處理
}
}

將 operation 放到 queue 中

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
YourOperation *operation = [[YourOperation alloc] init];
[queue addOperation:operation];

也可以直接將 block 放到 queue 中,但定義自己的 NSOperation 會比較好 debug。

[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// 代碼...
}];

NSOperation 還可以透過 maxConcurrentOperationCount 控制同時執行的數量,還有根據 queue 中的 operation 的 priority 排序,還可以在 operation 之間設 dependency。

而性能雖然比 GCD 要低一點,但大多數可以忽略不計。

使用 NSThread

使用這的問題是在我們的 code 中也做了建立 thread 的事情,可能導致 threads 爆炸。

FindMinMaxThread.h
@interface FindMinMaxThread : NSThread
@property (nonatomic) NSUInteger min;
@property (nonatomic) NSUInteger max;
- (instancetype)initWithNumbers:(NSArray *)numbers;
@end

// FindMinMaxThread.m
@implementation FindMinMaxThread {
NSArray *_numbers;
}

- (instancetype)initWithNumbers:(NSArray *)numbers
{
self = [super init];
if (self) {
_numbers = numbers;
}
return self;
}

- (void)main
{
NSUInteger min;
NSUInteger max;
// 進行相關數據的處理
self.min = min;
self.max = max;
}
@end

呼叫的方式

NSMutableSet *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];
}

使用 pthread

複雜不易使用

#import <pthread.h>

struct threadInfo {
uint32_t * inputValues;
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];

// 使用隨機數字填充 inputValues
for (size_t i = 0; i < count; ++i) {
inputValues[i] = arc4random();
}

// 開始4個尋找最小值和最大值的線程
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);
}
// 等待線程退出
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);
}
// 尋找 min 和 max
uint32_t min = UINT32_MAX;
uint32_t max = 0;
for (size_t i = 0; i < threadCount; ++i) {
min = MIN(min, results[i]->min);
max = MAX(max, results[i]->max);
free(results[i]);
results[i] = NULL;
}

NSLog(@"min = %u", min);
NSLog(@"max = %u", max);
return 0;
}
文章目錄
  1. 1. 使用 GCD
  2. 2. 使用 Operation Queues
  3. 3. 使用 NSThread
  4. 4. 使用 pthread
|