python - 为什么cython不编译逻辑或者到 `||`表达式?

标签 python c cython

例如,这里有一个 or 表达式:

c  = f1 == 0 or f1 - f0 > th

编译后的C代码:

__pyx_t_24 = (__pyx_v_f1 == 0);
if (!__pyx_t_24) {
} else {
  __pyx_t_23 = __pyx_t_24;
  goto __pyx_L5_bool_binop_done;
}
__pyx_t_24 = ((__pyx_v_f1 - __pyx_v_f0) > __pyx_v_th);
__pyx_t_23 = __pyx_t_24;
__pyx_L5_bool_binop_done:;
__pyx_v_c = __pyx_t_23;

为什么不输出这个?

__pyx_v_c = (__pyx_v_f1 == 0) || ((__pyx_v_f1 - __pyx_v_f0) > __pyx_v_th)

goto 版本是否比 || 更快?

最佳答案

使用以下两个文件:

test.c:

int main(int argc, char** argv) {
    int c, f0, f1, th;
    int hold, hold1;
    f0 = (int) argv[1];
    f1 = (int) argv[2];
    th = (int) argv[3];
    hold1 = (f0 == 0);
    if (!hold1) {

    } else {
        hold = hold1;
        goto done;
    }
    hold1 = (f1 - f0 > th);
    hold = hold1;
    done: c = hold;
    return c;
}

test2.c:

int main(int argc, char** argv) {
    int c, f0, f1, th;
    f0 = (int) argv[1];
    f1 = (int) argv[2];
    th = (int) argv[3];
    c = (f1 == 0) || (f1 - f0 > th);
    return c;
}

我必须将 f0f1th 分配给某些东西,这样编译器就不会只是返回 1 因为 C 规范指出 int 被初始化为 0 并且 f1 == 0 会产生 true,因此整个 bool 语句将产生 true 并且程序集将是:

main:
.LFB0:
    .cfi_startproc
.L2:
    movl    $1, %eax
    ret
    .cfi_endproc

使用带有 -S -O2 标志(启用优化)的 GCC 编译,test.stest2.s 变成:

main:
.LFB0:
    .cfi_startproc
    movl    8(%rsi), %edx
    movq    16(%rsi), %rdi
    movl    $1, %eax
    movq    24(%rsi), %rcx
    testl   %edx, %edx
    je  .L2
    subl    %edx, %edi
    xorl    %eax, %eax
    cmpl    %ecx, %edi
    setg    %al
.L2:
    rep
    ret
    .cfi_endproc

因此除非您禁用优化,其中带有 goto 的指令将多出大约 50% 的指令,否则结果将是相同的。

输出 C 代码难看的原因是解释器访问 AST 中节点的方式。当访问 节点时,解释器首先计算第一个参数,然后计算第二个。如果 bool 表达式复杂得多,解析起来就会容易得多。想象一下调用一个返回 bool 值的 lambda 函数(我不确定 Cython 是否支持这个);口译员必须遵循以下结构:

hold = ... evaluate the lambda expression...
if (hold) {
    result = hold;
    goto done; // short circuit
}
hold = ... evaluate the second boolean expression...
done:
...

在解释阶段进行优化将是一项艰巨的任务,因此 Cython 甚至不会打扰。

关于python - 为什么cython不编译逻辑或者到 `||`表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31868440/

相关文章:

python - 访问字典键值到键和值列表

python - 在 Python 中拒绝列表的快速方法

python - django-versatileimagefield 问题 : 'No matching distribution found for python-magic-bin' when deploying to Google App Engine Flex

c - g_atomic_int_get 保证对另一个线程的可见性?

检查一个值是否存在于 Cython 的数组中

python - 测试需要 Flask 应用程序或请求上下文的代码

c - Frama-C 用 "/*@ ensures"证明 While 循环

c - 为什么读取结构体指针字段无效?

c++ - 使用 C++ 时,如果没有 gil 编译错误,则不允许调用需要 gil 的函数

python - pickle.dump 由于 GIL 而阻塞多线程 python 应用程序中的主线程