【问题标题】:Which is faster in memory, ints or chars? And file-mapping or chunk reading?内存,整数或字符哪个更快?和文件映射或块读取?
【发布时间】:2010-04-07 05:09:55
【问题描述】:
好的,所以我之前编写了一个(相当未优化的)程序来将图像编码为 JPEG,但是,现在我正在使用 MPEG-2 传输流和其中的 H.264 编码视频。在我开始对所有这些进行编程之前,我很好奇处理实际文件的最快方法是什么。
目前我正在将 .mts 文件文件映射到内存中以进行处理,尽管我不确定(例如)将 100 MB 文件分块读取到内存中并处理它是否会更快方式。
这些文件需要大量的位移等来读取标志,所以我想知道当我引用一些内存时,一次读取 4 个字节作为整数或 1 个字节作为字符是否更快。我以为我在某处读到 x86 处理器已优化为 4 字节粒度,但我不确定这是否属实……
谢谢!
【问题讨论】:
标签:
c++
optimization
memory
file
integer
【解决方案1】:
如果您需要文件同步可用,内存映射文件通常是最快的可用操作。 (有一些异步 API 有时允许 O/S 重新排序事物以稍微提高速度,但这听起来对您的应用程序没有帮助)
您使用映射文件获得的主要优势是,您可以在文件仍被操作系统从磁盘读取时在内存中工作,并且您不必管理自己的锁定/线程文件读取代码。
内存引用明智,在 x86 上,无论您实际使用什么,一次都会读取整行内存。与非字节粒度操作相关的额外时间是指整数不需要字节对齐的事实。例如,如果事情没有在 4 字节边界上对齐,则执行 ADD 将花费更多时间,但对于像内存副本这样的事情,差别不大。如果您使用的是固有的字符数据,那么保持这种方式会比将所有内容读取为整数和位移位更快。
如果您正在执行 h.264 或 MPEG2 编码,无论如何,瓶颈可能是 CPU 时间而不是磁盘 i/o。
【解决方案2】:
如果您必须访问整个文件,将其读入内存并在那里进行处理总是更快。当然,这也是浪费内存,你必须以某种方式锁定文件,这样你就不会被其他应用程序并发访问,但无论如何优化都是关于妥协的。如果您跳过文件的(大)部分,内存映射会更快,因为您根本不必阅读它们。
是的,以 4 字节(甚至 8 字节)粒度访问内存比按字节访问内存要快。这又是一个折衷方案 - 取决于您之后对数据所做的事情,以及您在处理 int 中的位方面的熟练程度,总体上可能不会更快。
关于优化的一切:
- 测量
- 优化
- 测量
【解决方案3】:
这些是顺序比特流 - 您基本上一次使用它们,而无需随机访问。
在这种情况下,您无需花费大量精力来显式缓冲读取等:无论如何,操作系统都会为您缓冲它们。我之前写过H.264解析器,时间完全由解码和操作来控制,而不是IO。
我的建议是使用标准库来解析这些比特流。
Flavor 就是这样一个解析器,该网站甚至包括 MPEG-2 (PS) 和各种 H.264 部分(如 M-Coder)的示例。 Flavor 从类 c++ 语言构建原生解析代码;这是 MPEG-2 PS 规范的引述:
class TargetBackgroundGridDescriptor extends BaseProgramDescriptor : unsigned int(8) tag = 7
{
unsigned int(14) horizontal_size;
unsigned int(14) vertical_size;
unsigned int(4) aspect_ratio_information;
}
class VideoWindowDescriptor extends BaseProgramDescriptor : unsigned int(8) tag = 8
{
unsigned int(14) horizontal_offset;
unsigned int(14) vertical_offset;
unsigned int(4) window_priority;
}
【解决方案4】:
关于从内存中读取的最佳大小,我相信您会喜欢阅读 this post 关于内存访问性能和缓存效果的内容。
【解决方案5】:
关于内存映射文件需要考虑的一点是,大小大于可用地址范围的文件将只能映射文件的一部分。要访问文件的其余部分,需要取消映射第一部分并在其位置映射下一部分。
由于您正在解码 mpeg 流,您可能希望使用双缓冲方法和异步文件读取。它的工作原理是这样的:
blocksize = 65536 bytes (or whatever)
currentblock = new byte [blocksize]
nextblock = new byte [blocksize]
read currentblock
while processing
asynchronously read nextblock
parse currentblock
wait for asynchronous read to complete
swap nextblock and currentblock
endwhile