在 jupyter 笔记本中使用 cython 进行行分析

Posted

技术标签:

【中文标题】在 jupyter 笔记本中使用 cython 进行行分析【英文标题】:Line profiling with cython in jupyter notebook 【发布时间】:2019-08-21 12:46:33 【问题描述】:

我正在尝试在 jupyter notebook 中使用带有 cython 函数的 liner_profiler 库。它只工作了一半。我得到的结果只包含函数的第一行,没有分析结果。

%%cython -a
# cython: linetrace=True
# cython: binding=True
# distutils: define_macros=CYTHON_TRACE_NOGIL=1
import numpy as np
cimport numpy as np
from datetime import datetime
import math


cpdef np.int64_t get_days(np.int64_t year, np.int64_t month):
    cdef np.ndarray months=np.array([31,28,31,30,31,30,31,31,30,31,30,31])
    if month==2:
        if (year%4==0 and year%100!=0) or (year%400==0):
            return 29
    return months[month-1]

对于分析结果int只显示一行代码

    Timer unit: 1e-07 s

Total time: 0.0015096 s
File: .ipython\cython\_cython_magic_0154a9feed9bbd6e4f23e57d73acf50f.pyx
Function: get_days at line 15

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    15                                           cpdef np.int64_t get_days(np.int64_t year, np.int64_t month):

【问题讨论】:

你真的在调用这个函数吗?看起来您唯一要做的就是定义函数,因此只有 cpdef 行“运行” 是的,我在下一个单元格中调用它:%lprun -f get_days get_days(2019,3) 线路分析器似乎与 cdef 函数(或 cpdef)有问题。不确定这是 Cython 还是 line_profiler 的问题。 这也被视为问题 (github.com/pyutils/line_profiler/issues/13)。 【参考方案1】:

这可以看作是line_profiler 中的一个错误(如果它应该支持 Cython)。要获取分析函数的代码,line_profilerreads the pyx-file 并尝试在inspect.getblock 的帮助下提取代码:

...
# read pyx-file
all_lines = linecache.getlines(filename)
# try to extract body of the function strarting at start_lineno:
sublines = inspect.getblock(all_lines[start_lineno-1:])
...

但是,getblockcpdef-function 一无所知,因为 python 只有 def-functions,因此会产生错误的函数体(即只有签名)。

解决方法:

一个简单的解决方法是引入一个虚拟的def-function,它是cpdef-function 的标记,inspect.getblock 将产生整个 cpdef-function + sentinel 函数的主体,即:

%%cython
...
cpdef np.int64_t get_days(np.int64_t year, np.int64_t month):
    ...

def get_days_sentinel():
    pass

现在报告%lprun -f get_days get_days(2019,3) 如下所示:

Timer unit: 1e-06 s

Total time: 1.7e-05 s
File: XXXX.pyx
Function: get_days at line 10

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    10                                           cpdef np.int64_t get_days(np.int64_t year, np.int64_t month):
    11         1         14.0     14.0     82.4      cdef np.ndarray months=np.array([31,28,31,30,31,30,31,31,30,31,30,31])
    12         1          1.0      1.0      5.9      if month==2:
    13                                                   if (year%4==0 and year%100!=0) or (year%400==0):
    14                                                       return 29
    15         1          2.0      2.0     11.8      return months[month-1]
    16                                           
    17                                           def get_days_sentinel():
    18                                               pass

哨兵的尾随线仍然有些难看,但最好什么都看不到。

【讨论】:

以上是关于在 jupyter 笔记本中使用 cython 进行行分析的主要内容,如果未能解决你的问题,请参考以下文章

在Pycharm中使用jupyter笔记本

如何将numpy.ndarray分配给cython中nogil循环下的临时变量?

matplotlib:figimage 未显示在 Jupyter 笔记本中

使用 %matplotlib 笔记本时修复 Jupyter 笔记本中的绘图

在 Jupyter 笔记本中使用 matplotlib 创建图形时遇到问题 [重复]

如何使用官方Tensorflow docker容器在主机目录中保存和编辑Jupyter笔记本?