【发布时间】:2013-08-30 20:20:58
【问题描述】:
我正在编写一个常量时间字符串比较函数(用于 node.js),并且想禁用 V8 的优化编译器来实现这个单一的函数;使用命令行标志是不可能的。
我知道使用with{}(或try/catch)块会禁用优化编译器现在,但恐怕这个“功能”(错误)将在未来的版本中得到修复.
是否有一种不可变(并记录在案)的方式来禁用 V8 的优化编译器?
示例函数:
function constantTimeStringCompare( a, b ) {
// By adding a `with` block here, we disable v8's optimizing compiler.
// Using Object.create(null) ensures we don't have any object prototype properties getting in our way.our way.
with ( Object.create( null ) ){
var valid = true,
length = Math.max( a.length, b.length );
while ( length-- ) {
valid &= a.charCodeAt( length ) === b.charCodeAt( length );
}
// returns true if valid == 1, false if valid == 0
return !!valid;
}
}
还有一个 perf test 只是为了好玩。
【问题讨论】:
-
@DavidMurdoch 这称为线性时间,因为作为输入长度函数的执行时间是linear function。此外,这个函数可能比内置字符串比较 worse - 你缺少 三个 非常常见的快捷方式。
-
@DavidMurdoch 您的第一个问题是一个非常人为的场景。通常,运行时函数的“值”是在给定大小为
n的输入的情况下执行给定操作的次数。在您的情况下,此操作将是字符比较。因为这将是 longer 字符串的长度,所以a是常量并不重要,因为对于所有字符串b比a长,此函数的值将是 @ 987654330@。 (由于有无限数量的字符串长于a,而短于a的字符串数量有限,我们可以在分析中忽略较短的字符串。) -
@DavidMurdoch 另外,对于算法复杂度,您通常会考虑渐近复杂度。此处可以忽略检查引用相等性的快捷方式。我现在记得的另一个是检查长度是否相等,这是一个恒定时间检查,假设字符串长度事先已知。 (就像 Javascript 中的情况一样。)这意味着使用它的函数对于不等长度的输入将是恒定时间,对于等长输入是线性时间。所以是的,在这种情况下,省略这些检查将保证您的函数对于所有字符串都是 linear-time。
-
@DavidMurdoch 而使用这些快捷方式,理论上对于大多数字符串对来说是 constant-time,对于所有字符串对的无穷小子集来说是线性的。实际上,这取决于您的输入范围。即使没有它们,正如您所注意到的那样,由于
.length和max()的开销,函数也不会是完全线性的 -
@DavidMurdoch 是的。 It's also incorrect. 您的函数确定
a是否是b的前缀。 (为了使这成为一个恒定时间的比较,实际上您必须实现我提到的“优化”。)将所有操作计入计数器也没有任何意义。您通常分别计算一个或有时几个“代表性”操作的实例。对输入元素(在您的情况下为字符)的读取或写入很常见,输入元素之间的比较也是如此。您可以放心地忽略持续开销。
标签: javascript node.js google-chrome v8 compiler-optimization