对于iOS,在objective-c中同步对实例变量的读/写访问的最佳方式/最小等待方式是什么?
该变量经常被读取和写入(假设每秒读取和写入1000次).更改立即生效并不重要.读取与另一个读取数据一致并不重要,但写入必须迟早反映在读取获取的数据中.是否有一些允许这样的数据结构?
我想到了这个:
创建两个变量而不是一个变量; 让我们称他们为v[0]
和v[1]
.
对于每个v[i]
,创建一个并发调度队列,用于构建围绕它的读写器锁定机制.我们打电话给他们吧q[i]
.
现在进行写入操作,只有v[0]
写入,坚持锁定机制q[0]
.
在读取操作中,首先v[1]
读取并且仅在某个机会(例如1%)下读取操作在必要时查看v[0]
并更新v[1]
.
以下伪代码说明了这一点:
typedef int VType; // the type of the variable VType* v; // array of first and second variable dispatch_queue_t* q; // queues for synchronizing access to v[i] - (void) setV:(VType)newV { [self setV:newV at:0]; } - (void) setV:(VType)newV at:(int)i { dispatch_barrier_async(q[i], ^{ v[i] = newV; }); } - (VType) getV:(int)i { __block VType result; dispatch_sync(q[i], ^{ result = v[i]; }); return result; } - (VType) getV { VType result = [self getV:1]; if ([self random] < 0.01) { VType v0_result = [self getV:0]; if (v0_result != result) { [self setV:v0_result at:1]; result = v0_result; } } return result; } - (float) random { // some random number generator - fast, but not necessarily good }
这有以下好处:
v[0]
通常不会被读取操作占用.因此,写操作通常不会阻塞.
在大多数情况下,v[1]
不会被写入,因此对此操作的读操作通常不会阻塞.
但是,如果发生许多读操作,最终会将写入的值传播v[0]
到v[1]
.可能会错过某些值,但这对我的应用程序无关紧要.
你觉得怎么样,这有用吗?有更好的解决方案吗?
更新:
一些性能基准测试(一次读取和写入一个基准测试,尽可能快地完成1秒,一个读取队列,一个写入队列):
在iOS 4的iPhone 4S上:
runMissingSyncBenchmark: 484759 w/s runMissingSyncBenchmark: 489558 r/s runConcurrentQueueRWSyncBenchmark: 2303 w/s runConcurrentQueueRWSyncBenchmark: 2303 r/s runAtomicPropertyBenchmark: 460479 w/s runAtomicPropertyBenchmark: 462145 r/s
在iOS 7的模拟器中:
runMissingSyncBenchmark: 16303208 w/s runMissingSyncBenchmark: 12239070 r/s runConcurrentQueueRWSyncBenchmark: 2616 w/s runConcurrentQueueRWSyncBenchmark: 2615 r/s runAtomicPropertyBenchmark: 4212703 w/s runAtomicPropertyBenchmark: 4300656 r/s
到目前为止,原子财产获胜.极大.用a测试了SInt64
.
我期望并发队列的方法在性能上与原子属性相似,因为它是r/w-sync机制的标准方法.
当然,runMissingSyncBenchmark
有时候会产生一些读数,这些读数表明写入SInt64
是中途完成的.