joh*_*ers 1 concurrency cocoa grand-central-dispatch
如果我有两个不同的线程通过GCD访问一个NSMutableArray而一个只是创建一个基于可变数组的新数组而另一个线程正在从数组中删除记录,我应该期望这是一个问题吗?也就是说,我认为副本不应该只是"读取"数组,只是得到当时阵列中发生的一切?我没有在任何一个线程中枚举数组,但它仍然崩溃.一旦我删除了读取例程,它就可以正常工作.
这是"阅读":
dispatch_async(saveQueue, ^{
NSDictionary*tempstocks=[NSDictionary dictionaryWithDictionary:self.data];
Run Code Online (Sandbox Code Playgroud)
它崩溃在这个线程上: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[9]'
以下是另一个线程上发生的事情:
[self.data removeObjectForKey:item];
Run Code Online (Sandbox Code Playgroud)
我知道你在枚举的时候不能变异,但我认为在变异时读取是可以的,你可能不知道你得到了哪个版本的变异对象,但我不认为这是一个问题,但显然它是.也许该dictionaryWithDictionary方法正在执行首先看到X对象的操作,但是在例程完成时它包含XY对象,因此它self.data在运行时不会在一次捕捉中"捕获"整个字典,dictionaryWithDictionary而是枚举self.data哪个基本上是与枚举时的突变问题相同?
我猜你可以使用GCD创建三个不同的队列:一个用于保存,第二个用于其他东西,最后一个用于操作NSMutableArray.
dispatch_async(saveQueue, ^{
dispatch_barrier_async(_queue, ^{
NSDictionary*tempstocks=[NSDictionary dictionaryWithDictionary:self.data];
});
});
dispatch_async(anotherQueue, ^{
dispatch_barrier_async(_queue, ^{
[self.data removeObjectForKey:item];
});
});
Run Code Online (Sandbox Code Playgroud)
就像@synchronize使用GCD一样.
更多信息:GCD参考/ dispatch_barrier_async和http://www.mikeash.com/pyblog/friday-qa-2011-10-14-whats-new-in-gcd.html
编辑
我做了一些性能测试,以了解哪种方式更快:
- (void)usingSynchronized
{
dispatch_queue_t writeQyeue = dispatch_queue_create("com.tikhop.writeQyeue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(writeQyeue, ^{
for(size_t i=0; i<10000; i++)
@synchronized (arr) {
[arr replaceObjectAtIndex:0 withObject:[NSNumber numberWithInt:1]];
[arr replaceObjectAtIndex:0 withObject:[NSNumber numberWithInt:2]];
[arr replaceObjectAtIndex:0 withObject:[NSNumber numberWithInt:3]];
[arr replaceObjectAtIndex:0 withObject:[NSNumber numberWithInt:4]];
}
});
}
- (void)usingGCD
{
dispatch_queue_t writeQyeue = dispatch_queue_create("com.tikhop.writeQyeue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(writeQyeue, ^{
for(size_t i=0; i<10000; i++)
dispatch_barrier_async(_queue, ^{
[arr replaceObjectAtIndex:0 withObject:[NSNumber numberWithInt:5]];
[arr replaceObjectAtIndex:0 withObject:[NSNumber numberWithInt:6]];
[arr replaceObjectAtIndex:0 withObject:[NSNumber numberWithInt:7]];
[arr replaceObjectAtIndex:0 withObject:[NSNumber numberWithInt:8]];
});
});
}
arr = [NSMutableArray arrayWithCapacity:1];
[arr addObject:@(0)];
[self usingSynchronized];
[self usingGCD];
Run Code Online (Sandbox Code Playgroud)
我得到了以下结果:
