在我的应用程序中,我有大约300个NSData
个大小为0.5 MB的对象,我将它们全部按顺序编写到一个文件中,基本上是这个代码(写入一个0.5 MB的对象300次): / p>
- (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(第5代)和iPhone 6上,这个过程大约需要3秒钟,我想知道是否有更快的方法可以做到这一点。我尝试过使用NSFileManager
和NSFileHandle
方法,但它们花费的时间大致相同,这使我认为这是我遇到的基本I / O限制。
有没有办法更快地执行此操作(此代码应在任何设备上编译和运行)?
答案 0 :(得分:4)
这是我能够实现的最高性能,使用mmap&amp;的memcpy。
我的iPhone 6平均需要0.2秒才能运行,有些变化可达0.5秒左右。然而,YMMV看起来iPhone 6有两个不同的闪存存储提供商 - 一个是TLC,另一个是MLC--那些使用TLC的人将获得更好的结果。
这当然假设您可以使用异步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]);
});
}
答案 1 :(得分:2)
300 * 0.5 / 3 = 50MB / s,150MB数据看起来足够快。我想你已达到闪存存储WRITE速度限制。我相信您在后台线程中运行此代码,因此问题不在于阻止UI
答案 2 :(得分:1)
我建议的两个性能提示是:尝试关闭文件系统缓存或检查IO缓冲区大小。
“在读取您确定不再需要的数据时,例如流式传输大型多媒体文件,请告诉文件系统不要将该数据添加到文件系统缓存中。
应用可以使用fcntl
标志调用BSD F_NOCACHE
函数来启用或禁用文件的缓存。有关此功能的详细信息,请参阅fcntl
。“〜Performance Tips
或“在处理之前将大部分或全部数据读入内存”〜Performance Tips
iPhone 6使用16Gb SK海力士闪存〜[Teardown],顺序写入的理论极限约为40至70 Mb / s~ [NAND flash]。