【问题标题】:Use inline keyword for small, private functions in kotlin?对 kotlin 中的小型私有函数使用 inline 关键字?
【发布时间】:2019-05-26 11:27:24
【问题描述】:

我想知道,内联小型私有函数是否是个好主意? 在我的例子中,这些函数只是为了可读性而存在的,我知道它们只被调用了几次,所以更大的字节码大小是无关紧要的。
我知道,性能提升也可能微不足道,因为我没有传递函数类型(编译器实际上会警告我),但我们假设它是我们应用程序中的热点。

实际示例:

我有一个理论上无限的符号带(例如图灵机的带),它由两个数组(位置 = 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;
}

现在我想将 sn-p 翻译成 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 }

我个人认为,尤其是阅读功能,很容易阅读。
那么这是一个好主意吗?我可以忽略 IDE 的警告吗?还是我错过了什么?也许有一个最佳实践或其他模式来编写这些函数而无需重复(几乎)相同的行两次(对于位置 = 0)。

【问题讨论】:

  • 您必须进行测量(这在 Java 中很难正确完成)。但我会遵循 IDE 的建议。如果它是热点,JIT 可能无论如何都会内联代码。

标签: kotlin inline readability


【解决方案1】:

没有必要内联一个非常小的重复使用的函数,因为 JVM JIT 可能会在它认为合适的时候为您执行此操作。如果您内联该函数,您确实会在生成的字节码中造成一些膨胀,但否则,对于未从代码中的许多不同点调用的函数,也没有太大的危害。对于较大的内联函数、代码中许多地方使用的函数以及调用其他内联函数的内联函数,字节码膨胀更严重。您的案例不会造成太大影响。

短方法从内联中受益匪浅,正如您在When Short Methods Pay Off: JIT Inlining 中看到的那样:

如果满足以下条件,则方法可以内联:

  • 它很小 - 字节码大小小于 35 个字节(可以被 -XX:MaxInlineSize=X 标志覆盖)。
  • 它被频繁调用(它很热)并且小于 325 字节(可以被 -XX:MaxFreqInlineSize=X 标志覆盖)。

如果您超过这些参数或想要预热内联,您可以使用 inline 关键字使其在编译时发生。

您还希望在以下情况下在小函数上使用inline

  • 您希望允许将 lambda 传递给函数以执行 non-local return
  • 你想使用reified generic type parameters
  • 您正在编写一个函数,该函数接受一个高重复使用的 lambda,并且您希望避免对 lambda 的函数调用开销。通过内联这种类型的函数,Kotlin 编译器还内联了 lambda。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-01
    • 2019-10-15
    • 2011-05-24
    • 1970-01-01
    • 1970-01-01
    • 2017-12-21
    • 2013-01-29
    • 1970-01-01
    相关资源
    最近更新 更多