在我的应用程序中,我有大约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秒,我想知道是否有更快的方法来做到这一点。我尝试过使用NSFileManager
和NSFileHandle
方法,但它们花费的时间大致相同,这导致我认为这是我遇到的基本I/O限制。
有没有办法更快地做到这一点(这段代码应该在任何设备上编译和运行)?
发布于 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]);
});
}
发布于 2015-06-06 14:58:22
对于150MB的数据,300 * 0.5 /3= 50MB/s看起来足够快。我猜你达到了闪存写入速度的限制。我相信这段代码是在后台线程中运行的,所以问题不在于阻塞UI
发布于 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]。
https://stackoverflow.com/questions/30678597
复制相似问题