【问题标题】:Equivalent of java's concurrent hashmap in objective c等效于目标c中java的并发hashmap
【发布时间】:2013-11-19 09:51:15
【问题描述】:

我有一个由并行线程访问的NSMuableDictionary,其中很少有线程会枚举,很少有线程会发生变异。但是我们无法实现这一点,因为

“枚举期间不能改变集合”

.想到使用NSLock,但是在枚举完成之前锁定字典会导致性能下降。在java中,我们有并发hashmap,它足够聪明,可以处理这种情况。有没有更好的想法来实现这一点在iOS?.请帮忙。

【问题讨论】:

  • 并发哈希图在内部使用读/写锁

标签: java ios concurrency nsmutabledictionary concurrenthashmap


【解决方案1】:

对 Objective-C 容器的读/写访问通常不是线程安全的。

您可以通过将容器关联到专用调度队列,然后在该队列上执行所有读取和写入访问来解决并发问题。队列可以是串行的或并发的。

您可以在任何专用线程上调用以下方法。但是,我建议最终将您的实现切换为调度 lib。

在这里,我们创建一个串行队列:

dispatch_queue_t sync_queue = dispatch_queue_create("sync_queue", NULL);

可以异步进行写访问:

- (void) addItem:(id)item forKey:(NSString*)key {
    dispatch_async(sync_queue, ^{
        [self.dict setObject:item forKey:key];
    });
}

返回值的读访问必须是同步的:

- (id) itemForKey:(NSString*)key {
     __block id item;
     dispatch_sync(sync_queue, ^{
         item = [self.dict objectForKey:key];
     });
     return item;
}

您可以为任何任务定义类似的包装器:

- (void) iterate {
    dispatch_async(sync_queue, ^{
        for (id item in self.dict) {
            ...
        }
    });
}

使用并发队列:

dispatch_queue_t sync_queue = dispatch_queue_create("sync_queue", DISPATCH_QUEUE_CONCURRENT);

写访问可以异步进行,需要一个屏障:

- (void) addItem:(id)item forKey:(NSString*)key {
    dispatch_barrier_async(sync_queue, ^{
        [self.dict setObject:item forKey:key];
    });
}

返回值的读取访问必须是同步的,并且不需要屏障。 基本上,同步队列和并发队列没有区别:

- (id) itemForKey:(NSString*)key {
     __block id item;
     dispatch_sync(sync_queue, ^{
         item = [self.dict objectForKey:key];
     });
     return item;
}

【讨论】:

  • Pro:这是可行的,并且是 iOS 中的预期方式。缺点:它使您对地图的访问是异步的,并且通常会导致懒惰的开发人员将所有内容都扔到主队列中。
【解决方案2】:

objective-c 中没有等价物,但是您可以通过将元素保存在临时数组中来避免诸如“枚举时发生突变”之类的错误。有关更多信息,请参阅this 答案。

【讨论】:

【解决方案3】:

EDIT3:

这样就可以了: Implementing concurrent read exclusive write model with GCD

可能仍然存在一些限制,但至少您将拥有更细粒度的访问和来自多个线程的并发读取。

结束编辑 3:

将对字典的访问封装在一个类中,并在访问方法中使用@synchronized(self) {}。

编辑2: 没关系。这不会给你你想要的。将答案留在这里作为反模式。

编辑:

类似的东西

(在您的对象实现中)

- (void) setObjectSynchronized:(id) value forKey:(id) key {
  @synchronized(self) {
     [self.internalDictionary setObject:value forKey:key];
  }
}


- (void) objectForKeySynchronized:(id) key {
  @synchronized(self) {
     return [self.internalDictionary objectForKey:key];
  }
}

【讨论】:

  • 完成。省略了标题以及内部 NSMutableDictionary 的声明和初始化。现在不在我的 Mac 附近...
  • 好的,在枚举NSMutableDictionary的时候,如果我们调用上面你提到的两个方法,会抛出“Collections cannot be mutated”异常吗?。可以在枚举的时候调用上面提到的方法吗?字典?
  • 如果您使用我上面展示的两个访问器方法来访问实际的 NSMutableDictionary,则不会。查找@synchrnoized。它就像 Java 中的同步一样工作。是的,这与使用锁相同。如果你想要并发读写,那么你需要使用工作队列示例,即使在这里你也需要确保对底层字典对象的独占写入。
  • 不,抱歉,不是同时。您是否在我回答问题时编辑了问题,还是我在阅读时错过了该要求?
  • 查看我的 EDIT3 答案以获取您的解决方案的链接。
猜你喜欢
  • 2013-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多