在 kotlin 中对小型私有函数使用 inline 关键字?
Use inline keyword for small, private functions in kotlin?
我想知道内联小的私有函数是否是个好主意?
这些函数,在我的例子中,只是为了可读性的目的,我知道,它们只被调用了几次,所以更大的字节码大小是微不足道的。
我知道,性能提升也可能微不足道,因为我没有传递函数类型(编译器实际上会警告我这一点),但让我们假设它是我们应用程序中的热点。
实例:
我有一个 理论上 无限符号带(就像图灵机的那个),它由两个数组建模(位置 < 0 和位置 >= 的左右) 0,分别)。现在我有读写操作了,估计会被调用很多。
在 java 我有:
/**
* @param cell the cell
* @return the symbol at the specified cell
*/
public char read(int cell) {
char[] tape;
if (cell < 0) {
tape = left;
cell = -cell - 1;
} else {
tape = right;
}
return cell < tape.length ? tape[cell] : blank;
}
/**
* Writes a symbol to the specified cell.
* @param c the symbol
* @param cell the cell
*/
public void write(char c, int cell) {
char[] tape;
if (cell < 0) {
cell = -cell - 1;
if (cell >= left.length) left = expandArray(left, cell, blank);
tape = left;
} else {
if (cell >= right.length) right = expandArray(right, cell, blank);
tape = right;
}
tape[cell] = c;
}
现在我想将代码片段翻译成 kotlin,阅读内联函数并想出这个:
fun read(cell: Int = headPosition) = when {
cell < 0 -> read(left, -cell - 1)
else -> read(right, cell)
}
private inline fun read(tape: CharArray, cell: Int): Char {
return if (cell < tape.size) tape[cell] else blank
}
fun write(c: Char, cell: Int = headPosition) = when {
cell < 0 -> left = write(c, left, -cell - 1)
else -> right = write(c, right, cell)
}
private inline fun write(c: Char, tape: CharArray, cell: Int): CharArray = when {
cell >= tape.size -> expandArray(tape, cell, blank)
else -> tape
}.also { it[cell] = c }
我个人觉得,尤其是read函数,比较好读。
那么这是个好主意吗?我可以忽略 IDE 的警告吗?或者我错过了什么?也许有一个最佳实践或其他模式来编写这些函数而无需重复(几乎)相同的行两次(对于 position < 0 和 position >= 0)。
没有必要内联一个非常小的重复使用的函数,因为 JVM JIT 可能会在它认为合适的时候为您做这件事。如果你内联函数,你确实会导致生成的字节码有点膨胀,但除此之外,对于那些没有从代码中的许多不同点调用的函数,也没有太大的危害。对于较大的内联函数、代码中多处使用的函数以及调用其他内联函数的内联函数,字节码膨胀会更糟。你的案子 没有 造成什么影响。
短方法从内联中受益匪浅,正如您在 When Short Methods Pay Off: JIT Inlining:
中所读到的
A method is eligible for inlining if:
- It’s small – the bytecode size is smaller than 35 bytes (can be overridden by the -XX:MaxInlineSize=X flag).
- It’s called frequently (it’s hot) and it’s smaller than 325 bytes (can be overridden by the -XX:MaxFreqInlineSize=X flag).
如果您超过这些参数或想要 pre-warm 增加内联,您可以使用 inline
关键字使其在编译时发生。
您还希望在以下情况下对小函数使用 inline
:
- 您想允许传递给函数的 lambda 执行 non-local return
- 您想使用 reified generic type parameters.
- 您正在编写一个接受 lambda 的函数,该 lambda 被频繁使用,并且您希望避免对 lambda 的函数调用开销。通过内联这种类型的函数,Kotlin 编译器也内联了 lambda。
我想知道内联小的私有函数是否是个好主意?
这些函数,在我的例子中,只是为了可读性的目的,我知道,它们只被调用了几次,所以更大的字节码大小是微不足道的。
我知道,性能提升也可能微不足道,因为我没有传递函数类型(编译器实际上会警告我这一点),但让我们假设它是我们应用程序中的热点。
实例:
我有一个 理论上 无限符号带(就像图灵机的那个),它由两个数组建模(位置 < 0 和位置 >= 的左右) 0,分别)。现在我有读写操作了,估计会被调用很多。
在 java 我有:
/**
* @param cell the cell
* @return the symbol at the specified cell
*/
public char read(int cell) {
char[] tape;
if (cell < 0) {
tape = left;
cell = -cell - 1;
} else {
tape = right;
}
return cell < tape.length ? tape[cell] : blank;
}
/**
* Writes a symbol to the specified cell.
* @param c the symbol
* @param cell the cell
*/
public void write(char c, int cell) {
char[] tape;
if (cell < 0) {
cell = -cell - 1;
if (cell >= left.length) left = expandArray(left, cell, blank);
tape = left;
} else {
if (cell >= right.length) right = expandArray(right, cell, blank);
tape = right;
}
tape[cell] = c;
}
现在我想将代码片段翻译成 kotlin,阅读内联函数并想出这个:
fun read(cell: Int = headPosition) = when {
cell < 0 -> read(left, -cell - 1)
else -> read(right, cell)
}
private inline fun read(tape: CharArray, cell: Int): Char {
return if (cell < tape.size) tape[cell] else blank
}
fun write(c: Char, cell: Int = headPosition) = when {
cell < 0 -> left = write(c, left, -cell - 1)
else -> right = write(c, right, cell)
}
private inline fun write(c: Char, tape: CharArray, cell: Int): CharArray = when {
cell >= tape.size -> expandArray(tape, cell, blank)
else -> tape
}.also { it[cell] = c }
我个人觉得,尤其是read函数,比较好读。
那么这是个好主意吗?我可以忽略 IDE 的警告吗?或者我错过了什么?也许有一个最佳实践或其他模式来编写这些函数而无需重复(几乎)相同的行两次(对于 position < 0 和 position >= 0)。
没有必要内联一个非常小的重复使用的函数,因为 JVM JIT 可能会在它认为合适的时候为您做这件事。如果你内联函数,你确实会导致生成的字节码有点膨胀,但除此之外,对于那些没有从代码中的许多不同点调用的函数,也没有太大的危害。对于较大的内联函数、代码中多处使用的函数以及调用其他内联函数的内联函数,字节码膨胀会更糟。你的案子 没有 造成什么影响。
短方法从内联中受益匪浅,正如您在 When Short Methods Pay Off: JIT Inlining:
中所读到的A method is eligible for inlining if:
- It’s small – the bytecode size is smaller than 35 bytes (can be overridden by the -XX:MaxInlineSize=X flag).
- It’s called frequently (it’s hot) and it’s smaller than 325 bytes (can be overridden by the -XX:MaxFreqInlineSize=X flag).
如果您超过这些参数或想要 pre-warm 增加内联,您可以使用 inline
关键字使其在编译时发生。
您还希望在以下情况下对小函数使用 inline
:
- 您想允许传递给函数的 lambda 执行 non-local return
- 您想使用 reified generic type parameters.
- 您正在编写一个接受 lambda 的函数,该 lambda 被频繁使用,并且您希望避免对 lambda 的函数调用开销。通过内联这种类型的函数,Kotlin 编译器也内联了 lambda。