鉴于这种方法的替代方案是拥有大量构建,每个构建都包含以下内容:
int main()
{
printf(
#ifdef SWEDISH
"Hej världen\n"
#elsif ENGLISH
"Hello, World\n"
#elsif PORTUGUESE
"Olá, Mundo\n"
#else
#error Language not specified.
#endif
);
return 0l;
}
相反,我们得到:
int main()
{
printf(gettext("Hello, World\n"));
}
这很容易阅读和理解。
我不知道 gettext 实现的确切结构,但我希望它在加载后就是一个哈希表。可能是二叉树,但哈希表似乎更明智。
至于确切的开销,很难在上面加上一个数字 - 特别是,正如您所说,如果将某些东西交换到磁盘并且磁盘已停止,则需要 3-4 秒才能使磁盘加速。那么如何量化呢?gettext
是的,如果系统忙于执行内存密集型操作,则可能会换出所需的页面。
如果文件非常大,加载消息文件应该是一个很大的开销,但同样,如果磁盘没有旋转,并且文件没有缓存,那么会有几秒钟的开销。再次,如何量化。文件的大小显然与翻译(或母语)消息的实际大小成正比。
关于第2点:
据我所知,在 Linux 和 Windows 中,页面都是在“最近最少使用”(或其他一些使用统计)的基础上换出的,这与它们所在的位置无关。显然,翻译后的消息与实际代码位于不同的位置 - 源文件中没有 15 种不同翻译的列表,因此翻译是在运行时加载的,并且将位于与代码本身不同的位置。但是,这样的开销类似于以下之间的开销差异:
static const char *msg = "Hello, World\n";
和
static const char *msg = strdup("Hello, World\n");
鉴于文本字符串通常在程序的二进制文件中保存在一起,我认为它们与执行代码的“接近性”与堆中某处动态分配的内存没有显着不同。如果您gettext
足够频繁地调用该函数,则该内存将保持“当前”并且不会被换出。gettext
如果你一段时间不打电话,它可能会被换掉。但这适用于“最近没有使用存储在可执行文件中的字符串,因此它们被换掉了”。
3)我认为英语(或“未选择语言”)与任何其他语言变体完全相同。
我会再深入一点,首先需要早餐......
很不科学:
#include <libintl.h>
#include <cstdio>
#include <cstring>
static __inline__ unsigned long long rdtsc(void)
{
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}
int main()
{
char str[10000] = {};
char *s = str;
unsigned long long time;
for(int i = 0; i < 10; i++)
{
time = rdtsc();
s += sprintf(s, "Hello, World %d", i);
time = rdtsc() - time;
printf("Time =%lld\n", time);
}
printf("s = %s\n", str);
s = str;
strcpy(s, "");
for(int i = 0; i < 10; i++)
{
time = rdtsc();
s += sprintf(s, gettext("Hello, World %d"), i);
time = rdtsc() - time;
printf("Time =%lld\n", time);
}
printf("s = %s\n", str);
}
给出以下结果:
$ g++ -Wall -O2 intl.cpp
$ ./a.out
Time =138647
Time =9528
Time =6710
Time =5537
Time =5785
Time =5427
Time =5406
Time =5453
Time =5644
Time =5431
s = Hello, World 0Hello, World 1Hello, World 2Hello, World 3Hello, World 4Hello, World 5Hello, World 6Hello, World 7Hello, World 8Hello, World 9
Time =85965
Time =11929
Time =10123
Time =10226
Time =10628
Time =9613
Time =9515
Time =9336
Time =9440
Time =9095
s = Hello, World 0Hello, World 1Hello, World 2Hello, World 3Hello, World 4Hello, World 5Hello, World 6Hello, World 7Hello, World 8Hello, World 9
中的代码在dcigettext.c
平面字符串数组中混合使用二进制搜索,以及将字符串散列为 PJW 散列的散列函数(参见:http://www.cs.hmc.edu/~geoff/classes/hmc. cs070.200101/homework10/hashfuncs.html)。
因此,一旦应用程序启动,开销似乎在“非常明显”(计算时钟周期时),但不是很大。
在这两种情况下,第一次运行所需的确切时间sprintf
有所不同,所以我不会说“使用 gettext”在第一次调用时使 sprintf 更快 - 只是在这次运行中“运气不好”(我有一些其他变体的代码,它们在第一次调用时变化很大sprintf
,而在以后的调用中变化不大)。可能某些设置(可能缓存 [printf 导致缓存很可能被其他垃圾覆盖]、分支预测等)需要额外的时间......
现在,这显然不能回答您关于分页等问题。而且我没有尝试对我的“Hello, World”消息进行瑞典语、葡萄牙语或德语翻译。我仍然相信它不是很大,除非您确实每秒运行 100 次应用程序的实例化,并且该应用程序除了在进行一些简单的计算后在屏幕上打印一条消息之外并没有做太多事情,当然,这可能很重要.
找出它有多大差异的唯一真正方法是使用#define _(x) x
而不是编译相同的应用程序#define _(x) gettext(x)
,看看您是否注意到任何差异。
我仍然认为“分页”是一个红鲱鱼。如果机器处于高内存压力下,那么无论如何它都会运行缓慢(如果我在我的机器上编写一段分配 16GB [机器中有 16GB RAM] 的代码,几乎除了键盘本身之外的所有东西(可以闪烁数字锁定 LED)并且鼠标指针本身(可以在屏幕上移动鼠标指针)无响应)。