Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 在内存受限的多线程iOS应用程序中存储大量非结构化数据的最佳方法?_Iphone_Objective C_Xcode - Fatal编程技术网

Iphone 在内存受限的多线程iOS应用程序中存储大量非结构化数据的最佳方法?

Iphone 在内存受限的多线程iOS应用程序中存储大量非结构化数据的最佳方法?,iphone,objective-c,xcode,Iphone,Objective C,Xcode,几个月来,我一直在我的应用程序中绕圈子解决这个问题。我已经尝试了许多自制的解决方案,并将解释我在这里的工作,但我希望有人能提出一个更好的解决方案,我错过了 基本问题是:我有(可能)数千个项目需要我的应用程序随时访问。NSMutableDictionary通常是我表示每个项的第一种方法,因为每个项可能有几个到数百个属性。但其余的要求让事情变得棘手: 每个项目都可以由任何线程读取或写入 每个项目都需要存储到磁盘,以便在会话之间检索 有(可能)太多的项(和太多的数据),如果同时将它们全部放在内存中,可

几个月来,我一直在我的应用程序中绕圈子解决这个问题。我已经尝试了许多自制的解决方案,并将解释我在这里的工作,但我希望有人能提出一个更好的解决方案,我错过了

基本问题是:我有(可能)数千个项目需要我的应用程序随时访问。NSMutableDictionary通常是我表示每个项的第一种方法,因为每个项可能有几个到数百个属性。但其余的要求让事情变得棘手:

  • 每个项目都可以由任何线程读取或写入
  • 每个项目都需要存储到磁盘,以便在会话之间检索
  • 有(可能)太多的项(和太多的数据),如果同时将它们全部放在内存中,可能会导致内存问题
  • 我想使用CoreData,因为苹果非常喜欢它,但我遇到了很多问题。每个项都没有确定的结构,因此没有好的方法来构造数据模型。此外,查询数据导致单个.sqlite文件成为瓶颈,这意味着当许多线程试图同时检索项目时,等待时间(延迟)变得非常快

    我有一个有效的解决方案,但它有问题。下面是一段代码,我将在下面解释它的作用

    - (NSObject*) getValue:(NSString*)key {
        @synchronized(self) {
            if(!_cached_obj) { // private variable in this object
                _cached_obj = [self loadFromDisk]; // simply loads the NSDictionary from a file
            }
            _last_access = time(nil);//don't release for a while
            return [_cached_obj valueForKey:key];
        }
    }
    - (void) setValue:(NSObject*)value forKey:(NSString*)key {
        @synchronized(self) {
            [self getValue:key];//ensures the cache is active
            [_cached_obj setValue:value forKey:key];
            _needs_save = true;
        }
    }
    - (void) clean {
        if(!_cached_obj)
            return;
        @synchronized(self) {
            if(_needs_save)
            {
                [self writeToFile];//writes the cache obj to a file
                _needs_save = NO;
            }
    
            NSTimeInterval elapsed = time(nil) - _last_access;
            if(elapsed > 20)
            {
                [_cached_obj release];
                _cached_obj = nil;
            }
        }
    }
    
    • 当我需要一个项目的数据时,会调用getValue函数。它尝试使用缓存对象(NSMutableDictionary)。如果缓存对象为空,则在返回之前从磁盘加载对象
    • setValue函数按预期工作,但也设置保存标志
    • “clean”函数由后台线程在10秒计时器上运行。这负责将项目保存到磁盘并取消缓存数据以节省内存
    我不喜欢我的方法的一点是,基于我对@synchronized的使用,有很多信号量等待。有时,这也意味着主线程在等待磁盘读/写时会阻塞,这很痛苦

    我是否缺少更好的数据结构或存储机制

    谢谢


    编辑:更多信息:
    “getValue”函数返回的速度也是非常重要的,即使它没有阻塞主线程。例如,考虑我在后台线程中通过10K项搜索的场景。我需要从每个10k对象中获取一个值。按照我目前的机制,它可以工作,但是从磁盘加载每个非缓存对象非常耗时,在我的iPhone4上需要大约20秒。我知道这可能只是“我必须付出的代价”。但是,也许将数据存储在较小的数据块中会有所帮助?例如,不要将整个项目存储为字典,而是存储为不同对象的集合。

    据我所知,您分析了应用程序,配置文件显示@synchronize块是最大的性能瓶颈。对吧?

    好吧,我并不太惊讶:正如您所指出的,您在按住互斥键的同时读写文件。此外,您同时只允许一个线程,而您可以轻松地允许多个读卡器或一个写卡器访问缓存

    确定的锁定操作:

    • 获取值->在缓存中获取值,在磁盘上获取值如果不在缓存中,将值放入缓存
    • 设置值->在缓存中获取值,如果不在缓存中,则在磁盘上获取值,将值放入缓存,将新值放入缓存
    • 清理->保存缓存,清空缓存
    那么,基本操作是:

    • 在缓存中获取值
    • 获取磁盘上的值
    • 将值放入缓存
    • 保存缓存
    • 空缓存
    很容易确定这些简单操作的并发性,然后修改锁以确保所有操作都能很好地相互配合

    您可以允许多个读卡器或一个写卡器访问缓存。一个线程可以读取(或写入)磁盘,而无需锁定缓存。从磁盘读取的值稍后将作为写入程序在缓存中设置。因此,缓存有一个读写锁,文件有一个互斥锁。设定值序列也有点令人费解。我不认为从文件中读取旧值以立即替换它有什么意义。如果需要缓存数据结构准备就绪,只需确保它们不触发文件操作即可

    所有这些也可以使用GCD实现,避免大部分锁(如果不是全部的话)

    在不引入大量复杂性或改变应用程序线程模型的情况下,有足够的空间来减少冲突。我认为GCD提供了更多的机会,但您必须从队列和操作的角度来考虑,而不是从线程的角度来考虑,这在第一眼看来并不容易


    我不会说修改锁就足够了,您可能还需要改进数据读取和保存到磁盘的方式,但要从锁开始。您可能会感到惊讶。

    您能更深入地解释一下您正在处理的数据吗?您的用例是什么?为什么要处理这么多具有可变或动态结构的项?您是否考虑过只运行
    clean
    以响应内存警告,以此作为减少缓存未命中的一种方法?您还可以通过在后台为您想要的“单个值”编制索引来获取值,但这取决于事物变化的频率。