gpt4 book ai didi

objective-c - 从多个线程写入文件

转载 作者:太空狗 更新时间:2023-10-30 03:35:23 25 4
gpt4 key购买 nike

我正在用 Objective-C 编写一个下载管理器,它同时从多个段下载文件以提高速度。文件的每一段都在一个线程中下载。

起初,我想将每个片段写在不同的文件中,并在下载结束时将所有文件放在一起。但出于多种原因,这不是一个好的解决方案。

因此,我正在寻找一种在特定位置写入文件并且能够处理多线程的方法,因为在我的应用程序中,每个段都在一个线程内下载。在 Java 中,我知道 FileChannel 可以完美地完成这个技巧,但我不知道在 Objective-C 中。

最佳答案

到目前为止给出的答案有一些明显的缺点:

  • 使用系统调用的文件 i/o 在锁定方面肯定有一些缺点。
  • 在内存中缓存部件会导致内存受限环境中的严重问题。 (即任何计算机)

线程安全、高效、无锁的方法是使用内存映射,其工作方式如下:

  • 创建(至少)所需总长度的结果文件
  • open() 读/写文件
  • mmap() 它到内存中的某个地方。该文件现在“存在于”内存中。
  • 将接收到的部分写入内存中文件中正确的偏移量
  • 跟踪是否已收到所有片段(例如,通过在主线程上为接收和存储的每个片段发布一些选择器)
  • munmap() 内存和 close() 文件

实际写入由内核处理 - 您的程序永远不会发出任何形式的 write 系统调用。内存映射通常没有什么缺点,广泛用于共享库等。

更新:一段代码说了1000多字……这是Mecki基于锁的多线程文件编写器的mmap版本。请注意,写入被简化为一个简单的 memcpy,它不会失败(!!),因此没有要检查的 BOOL success。性能等同于基于锁的版本。 (通过并行写入 100 个 1mb block 进行测试)

关于对基于 mmap 的方法的“矫枉过正”的评论:这使用更少的代码行,不需要锁定,写入时阻塞的可能性较小,不需要检查返回值在写作上。唯一的“矫枉过正”是它要求开发人员理解另一个概念,而不是良好的旧读/写文件 I/O。

直接读入映射内存区域的可能性被排除在外,但实现起来非常简单。您可以直接read(fd,i_filedata+offset,length);recv(socket,i_filedata+offset,length,flags);直接进入文件。

@interface MultiThreadFileWriterMMap : NSObject
{
@private
FILE * i_outputFile;
NSUInteger i_length;
unsigned char *i_filedata;
}

- (id)initWithOutputPath:(NSString *)aFilePath length:(NSUInteger)length;
- (void)writeBytes:(const void *)bytes ofLength:(size_t)length
toFileOffset:(off_t)offset;
- (void)writeData:(NSData *)data toFileOffset:(off_t)offset;
- (void)close;
@end

#import "MultiThreadFileWriterMMap.h"
#import <sys/mman.h>
#import <sys/types.h>

@implementation MultiThreadFileWriterMMap

- (id)initWithOutputPath:(NSString *)aFilePath length:(NSUInteger)length
{
self = [super init];
if (self) {
i_outputFile = fopen([aFilePath UTF8String], "w+");
i_length = length;
if ( i_outputFile ) {
ftruncate(fileno(i_outputFile), i_length);
i_filedata = mmap(NULL,i_length,PROT_WRITE,MAP_SHARED,fileno(i_outputFile),0);
if ( i_filedata == MAP_FAILED ) perror("mmap");
}
if ( !i_outputFile || i_filedata==MAP_FAILED ) {
[self release];
self = nil;
}
}
return self;
}

- (void)dealloc
{
[self close];
[super dealloc];
}

- (void)writeBytes:(const void *)bytes ofLength:(size_t)length
toFileOffset:(off_t)offset
{
memcpy(i_filedata+offset,bytes,length);
}

- (void)writeData:(NSData *)data toFileOffset:(off_t)offset
{
memcpy(i_filedata+offset,[data bytes],[data length]);
}

- (void)close
{
munmap(i_filedata,i_length);
i_filedata = NULL;
fclose(i_outputFile);
i_outputFile = NULL;
}

@end

关于objective-c - 从多个线程写入文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9319874/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com