代码之家  ›  专栏  ›  技术社区  ›  Segev

访问文件属性与访问sqlite记录

  •  7
  • Segev  · 技术社区  · 10 年前

    在我们的一个应用程序中,我被要求记录图像的最后修改日期。通过这种方式,我可以向服务器检查某个图像是否已更改,并相应地更新缓存。

    我的第一个方法是访问文件属性并执行比较,但网上有几个地方提到了延迟方面的严重瓶颈。

    我的第二个选择是创建一个SQLite表来管理它 fmdb )

    我决定写一个简单的延迟测试。在下一个测试中,我将访问500个文件属性和500个sqlite记录:

    - (void)latencyTest
    {
        NSMutableArray *arrayTest1 = [[NSMutableArray alloc]init];
        NSMutableArray *arrayTest2 = [[NSMutableArray alloc]init];
        FMResultSet *results = [_database executeQuery:@"SELECT * FROM `tb_media`"];
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"dd-MM-yyyy HH:mm:ss:SSS"];
        NSLog(@"Time1: %@",[formatter stringFromDate:[NSDate date]]);
        int i=1;
        while(i<501)
        {
            NSString *test = [NSString stringWithFormat:@"%@/_media/media/19/%d.jpg",_outputPath,i];
            NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:test error:nil];
            NSDate *dateX = [attributes fileModificationDate];
            [arrayTest1 addObject:dateX];
            i++;
        }
        NSLog(@"Time2: %@",[formatter stringFromDate:[NSDate date]]);
        while([results next])
        {        
            NSDate *myDate = [NSDate dateWithTimeIntervalSince1970:[results intForColumn:@"last_update"]];
            [arrayTest2 addObject:myDate];
        }
        NSLog(@"Time3: %@",[formatter stringFromDate:[NSDate date]]);
    }
    

    结果:

        //iPhone 5 (Actual Device) 500 Pics
    
        Files Start:                 05-03-2014 09:31:20:375 
        Files End & Sqlite start:    05-03-2014 09:31:20:491 
        Sqlite end:                  05-03-2014 09:31:20:507
    
        Files Start:                 05-03-2014 09:31:56:305 
        Files End & Sqlite start:    05-03-2014 09:31:56:421 
        Sqlite end:                  05-03-2014 09:31:56:437
    
        Files Start:                 05-03-2014 09:32:19:053 
        Files End & Sqlite start:    05-03-2014 09:32:19:170 
        Sqlite end:                  05-03-2014 09:32:19:187
    

    正如你所看到的,结果几乎相同。 我的问题是:

    1. 我假设每次访问一个文件时使用 attributesOfItemAtPath 将 花费的时间比sql长得多。我错过了什么吗?

    2. ItemAtPath的属性 真正访问文件或iOS 文件系统将所有属性保存在某种数据库中 方便访问?

    3. 看到以上结果后,我决定 ItemAtPath的属性 方法还有什么我没有 考虑传递sqlite?

    2 回复  |  直到 10 年前
        1
  •  5
  •   Kunal Balani    10 年前

    在我讨论解决方案之前,您的评估策略存在某些问题。

    1) 您还没有合并NSLog和while循环所花费的时间。75%的时间被他们占用 而您只需要比较intForColumn与attributesOfItemAtPath。正确的方法是运行仪器 Timer Profiler 并比较检索单个记录的时间。

    2) 您已将FMDB用作文件管理器。FMDB内部序列化文件中的数据。FMDB/SQL Lite的核心在于它的数据结构,特别是你根本没有使用过的索引。 所以,即使您比较记录所花费的时间,您也会发现FMDB比文件管理器花费更多的时间,因为以特定格式序列化数据需要额外的开销。

    3) X条记录的访问时间与对磁盘(硬盘驱动器)而非堆进行访问的次数进行比较。在这两种情况下,您所做的都是数据存储的堆访问。所以你根本看不出有什么不同。

    这是否意味着文件管理器优于FMDB,绝对不是!! 以下是几个原因:

    FMDB只有在配置为这样做时才能表现良好。 FMDB的核心在于两个方面:分页(缓存到堆中)和索引。 让我一次一个地向你解释。

    1) 假设您正在尝试访问100个图像的时间戳。其中每个图像具有1000个时间戳。这意味着您必须对数据存储进行100*1000=100000次访问。 如果映像很小,则Filemanager会将文件加载到堆中,访问速度将比FMDB快,但如果没有足够的堆空间,则应用程序会发出内存警告,并从磁盘访问文件,而不是从缓存访问文件,这会慢得多。

    所以它是一个二进制状态,要么全部来自堆,要么全部从磁盘

    FMDB优于此状态,并根据可用堆空间检索部分记录。当你有一大堆记录时,这会使访问速度更快。

    测试此场景的理想方法是对至少10000个图像(而不是时间戳)运行函数延迟测试。这样,与总时间相比,日志时间和迭代速度可以忽略不计。

    2) 索引结构,这可以追溯到SQLLite的基础知识。您可能需要添加一个额外的属性调用作为对图像的访问数,并在此基础上对表进行索引。这将大大提高性能。使用Filemeanger不太可能。

    我推荐的解决方案。
    1) 如果您的数据小于2 MB(图像加上时间戳),请使用Filemenager

    2) 如果数据>2MB用于核心数据/FMDB。

    核心数据具有针对多线程环境的额外性能调整,以及许多其他功能,如加密的无缝集成。

        2
  •  0
  •   fz.    10 年前

    首先,正如@kunal所说,你的基准测试方法不是确定性的,会误导你的决策。

    话虽如此,attributesOfItemAtPath:如果您只需要修改日期和性能,则会产生一些开销。你能做的就是使用 lstat 相反这与您的情况类似(请注意,我删除了数组以避免基准测试上不必要的开销):

    #import <sys/stat.h>
    
    - (void)latencyTest
    {
        // *********************** Test 1 ***********************************//
        double t = CACurrentMediaTime();
        for (NSInteger i = 1; i < 748; i++)
        {
            NSString *path = [NSString stringWithFormat:kMediaPath, i];
            NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path
                                                                                        error:nil];
            NSDate *dateX = [attributes fileModificationDate];
        }
        double total = CACurrentMediaTime() - t;
        NSLog(@"Total time fileManager: %fs, average per read: %fs", total, total / 747.f);
    
        // *********************** Test 2 ***********************************//
        struct stat linfo;
        t = CACurrentMediaTime();
        for (NSInteger i = 1; i < 748; i++)
        {
            NSString *path = [NSString stringWithFormat:kMediaPath, i];
            lstat([path cStringUsingEncoding:NSUTF8StringEncoding], &linfo);
            NSDate *dateX = [NSDate dateWithTimeIntervalSince1970:linfo.st_mtime];
        }
        total = CACurrentMediaTime() - t;
        NSLog(@"Total time lstat: %fs, average per read: %fs", total, total / 747.f);
    }
    

    对于748幅图像的输入,我的结果是:

    // Simulator (iOS 7.1)
    
    Total time fileManager: 0.061365s, average per read: 0.000082s
    Total time lstat: 0.004313s, average per read: 0.000006s
    
    // iPhone 5s Device (iOS 7.1)
    
    Total time fileManager: 0.019299, average per read: 0.000026
    Total time lstat: 0.008520, average per read: 0.000011