【发布时间】:2016-06-12 14:18:54
【问题描述】:
我目前正在将我的爱好项目从std::fstream 迁移到SDL_RWops(因为SDL_RWops 是我在Android 上加载资产的唯一简单选择)。
从文件中读取工作完美,但写入文件非常慢。
考虑以下测试用例:
C 标准 IO - 0.217193 秒
std::FILE *io = std::fopen("o.txt", "w");
for (int i = 0; i < 1024*1024*4; i++)
std::putc('0', io);
std::fclose(io);
C++ 流 - 0.278278 秒
std::ofstream io("o.txt");
for (int i = 0; i < 1024*1024*4; i++)
io << '0';
io.close();
SDL_RWops:- 17.9893 秒
SDL_RWops *io = SDL_RWFromFile("o.txt", "w");
for (int i = 0; i < 1024*1024*4; i++)
io->write(io, "0", 1, 1);
io->close(io);
所有测试用例均使用 g++ 5.3.0 (mingw-w64) x86 和 -O3 编译。我用过 SDL 2.0.4。
我也尝试过 -O0,结果相似(慢 0.02 到 0.25 秒)。
查看这些结果后,我有一个明显的问题:
为什么 SDL_RWops 写入性能这么差?
我该怎么做才能让它表现得更好?
编辑:这是windows_file_write()(来自SDL)的代码,这是io->write 应该指向的。它应该做缓冲输出,但我不确定它是如何工作的。
static size_t SDLCALL
windows_file_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
{
size_t total_bytes;
DWORD byte_written;
size_t nwritten;
total_bytes = size * num;
if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE || total_bytes <= 0 || !size)
return 0;
if (context->hidden.windowsio.buffer.left) {
SetFilePointer(context->hidden.windowsio.h,
-(LONG)context->hidden.windowsio.buffer.left, NULL,
FILE_CURRENT);
context->hidden.windowsio.buffer.left = 0;
}
/* if in append mode, we must go to the EOF before write */
if (context->hidden.windowsio.append) {
if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) ==
INVALID_SET_FILE_POINTER) {
SDL_Error(SDL_EFWRITE);
return 0;
}
}
if (!WriteFile
(context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) {
SDL_Error(SDL_EFWRITE);
return 0;
}
nwritten = byte_written / size;
return nwritten;
}
【问题讨论】:
-
也许
SDL_RWops没有缓冲它的输出。尝试将所有内容放在一个数组中并一次写入。 -
@BenjaminLindley 看起来你是对的。一次写入整个数组给我 0.006 秒。但我不明白为什么 SDL_RWops 不缓冲输出。 SDL 文档暗示它可能会这样做。
-
关于您的编辑:您可以看出它对于小型写入很慢,因为每个
windows_file_write都直接调用WriteFile。磁盘访问肯定会被 Windows 缓冲(除非在CreateFile期间明确要求不缓冲),但它没有缓冲的是 API 调用的数量,因此您会得到很多系统调用开销。 -
我想知道
SDL_RWFromFile与使用标准库相比应该有什么优势,但这是另一个问题。