首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >有没有办法加速这个文件I/O代码?

有没有办法加速这个文件I/O代码?
EN

Stack Overflow用户
提问于 2015-06-06 11:22:17
回答 3查看 1.7K关注 0票数 16

在我的应用程序中,我有大约300个0.5MB大小的NSData对象,我使用下面的代码(它将一个0.5MB对象写300次)按顺序将它们都写到一个文件中:

- (void)createFile {

    // create .5 MB block to write
    int size = 500000;
    Byte *bytes = malloc(size);
    for (int i = 0; i < size; i++) {
        bytes[i] = 42;
    }
    NSData *data = [NSData dataWithBytesNoCopy:bytes length:size 
       freeWhenDone:YES];

    // temp output file
    NSUUID *uuid = [NSUUID UUID];
    NSString *path = [[NSTemporaryDirectory() 
        stringByAppendingPathComponent:[uuid UUIDString]] 
        stringByAppendingPathExtension:@"dat"];
    NSOutputStream *outputStream = [[NSOutputStream alloc] 
        initToFileAtPath:path append:NO];
    [outputStream open];

    double startTime = CACurrentMediaTime();

    NSInteger totalBytesWritten;
    NSInteger bytesWritten;
    Byte *readPtr;

    for (int i = 0; i < 300; i++) {

        // reset read pointer to block we're writing to the output
        readPtr = (Byte *)[data bytes];
        totalBytesWritten = 0;

        // write the block
        while (totalBytesWritten < size) {
            bytesWritten = [outputStream write:readPtr maxLength:size 
                - totalBytesWritten];
            readPtr += bytesWritten;
            totalBytesWritten += bytesWritten;
        }

    }

    double duration = CACurrentMediaTime() - startTime;
    NSLog(@"duration = %f", duration);

    [outputStream close];

}

在我的iPod (第五代)和我的iPhone 6上,这个过程大约需要3秒,我想知道是否有更快的方法来做到这一点。我尝试过使用NSFileManagerNSFileHandle方法,但它们花费的时间大致相同,这导致我认为这是我遇到的基本I/O限制。

有没有办法更快地做到这一点(这段代码应该在任何设备上编译和运行)?

EN

回答 3

Stack Overflow用户

发布于 2015-06-09 13:35:53

这是我使用mmap & memcpy所能达到的最高性能。

在我的iPhone 6上运行平均需要0.2秒,一些变化高达0.5秒左右。然而,iPhone 6似乎有两种不同的闪存提供商-一种是薄层存储,另一种是多层存储-那些使用薄层存储的人将获得更好的结果。

当然,这假设您可以接受异步I/O。如果您确实需要一些同步的东西,请寻找其他解决方案。

- (IBAction)createFile {
  NSData *data = [[self class] dataToCopy];

  // temp output file
  NSUUID *uuid = [NSUUID UUID];
  NSString *path = [[NSTemporaryDirectory()
                     stringByAppendingPathComponent:[uuid UUIDString]]
                    stringByAppendingPathExtension:@"dat"];

  NSUInteger size = [data length];
  NSUInteger count = 300;

  NSUInteger file_size = size * count;

  int fd = open([path UTF8String], O_CREAT | O_RDWR, 0666);
  ftruncate(fd, file_size);

  void *addr = mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

  double startTime = CACurrentMediaTime();
  static dispatch_queue_t concurrentDataQueue;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    concurrentDataQueue = dispatch_queue_create("test.concurrent", DISPATCH_QUEUE_CONCURRENT);
  });

  for (int i = 0; i < count; i++) {
    dispatch_async(concurrentDataQueue, ^{
      memcpy(addr + (i * size), [data bytes], size);
    });
  }

  dispatch_barrier_async(concurrentDataQueue, ^{
    fsync(fd);

    double duration = CACurrentMediaTime() - startTime;
    NSLog(@"duration = %f", duration);

    munmap(addr, file_size);
    close(fd);
    unlink([path UTF8String]);
  });
}
票数 4
EN

Stack Overflow用户

发布于 2015-06-06 14:58:22

对于150MB的数据,300 * 0.5 /3= 50MB/s看起来足够快。我猜你达到了闪存写入速度的限制。我相信这段代码是在后台线程中运行的,所以问题不在于阻塞UI

票数 2
EN

Stack Overflow用户

发布于 2015-06-09 14:44:26

我可以推荐的两个性能技巧是:尝试关闭文件系统缓存或检查IO缓冲区大小。

“在读取您确定不久将不再需要的数据时,例如流式传输大型多媒体文件,告诉文件系统不要将该数据添加到文件系统缓存中。

应用程序可以调用带有F_NOCACHE标志的BSD fcntl函数来启用或禁用文件的缓存。有关此函数的详细信息,请参阅fcntl。“~Performance Tips

或者“在处理数据之前将大量或全部数据读入内存”~Performance Tips

iPhone 6使用16 Mb hynix闪存~[Teardown],理论上顺序写入限制约为40至70 Mb/s~[NAND flash]

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30678597

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档