将纯 Python 空操作函数与用 @numba.jit 修饰的空操作函数进行比较,即:
import numba
@numba.njit
def boring_numba():
pass
def call_numba(x):
for t in range(x):
boring_numba()
def boring_normal():
pass
def call_normal(x):
for t in range(x):
boring_normal()
如果我们用 %timeit 计时,我们会得到以下结果:
%timeit call_numba(int(1e7))
792 ms ± 5.51 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit call_normal(int(1e7))
737 ms ± 2.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
一切都非常合理; numba 函数的开销很小,但并不多。
但是,如果我们使用 cProfile 分析这段代码,我们会得到以下信息:
cProfile.run('call_numba(int(1e7)); call_normal(int(1e7))', sort='cumulative')
ncalls tottime percall cumtime percall filename:lineno(function)
76/1 0.003 0.000 8.670 8.670 {built-in method builtins.exec}
1 6.613 6.613 7.127 7.127 experiments.py:10(call_numba)
1 1.111 1.111 1.543 1.543 experiments.py:17(call_normal)
10000000 0.432 0.000 0.432 0.000 experiments.py:14(boring_normal)
10000000 0.428 0.000 0.428 0.000 experiments.py:6(boring_numba)
1 0.000 0.000 0.086 0.086 dispatcher.py:72(compile)
cProfile 认为调用 numba 函数的开销很大。
这扩展到“真实”代码:我有一个简单地调用我的昂贵计算的函数(计算是 numba-JIT 编译的),cProfile 报告说包装函数占用了大约三分之一的时间总时间。
我不介意 cProfile 增加一些开销,但如果它在增加开销的位置上存在大量不一致,那它就不是很有帮助了。有谁知道为什么会发生这种情况,是否有什么办法可以解决,和/或是否有任何其他分析工具不会与 numba 交互不良?
最佳答案
当您创建一个 numba 函数时,您实际上创建了一个 numba Dispatcher 对象。该对象将对 boring_numba 的“调用”“重定向”到正确的(就类型而言)内部“jitted”函数。因此,即使您创建了一个名为 boring_numba 的函数 - 该函数并未被调用,但被调用的是一个基于您的函数的编译函数。
这样你就可以看到函数 boring_numba 在分析 的过程中被调用(即使它不是,调用的是 对象需要 Hook 到当前线程状态并检查是否有分析器/跟踪器正在运行,如果"is",它看起来像是调用了 CPUDispatcher.__call__) Dispatcherboring_numba。最后一步是导致开销是因为它必须为 boring_numba 伪造一个“Python 堆栈框架”。
更具技术性:
当您调用 numba 函数 boring_numba 时,它实际上调用了 Dispatcher_Call这是 call_cfunc 的包装这是主要的区别:当你有一个运行分析器的代码时,处理分析器的代码构成了函数调用的大部分(只需比较 if (tstate->use_tracing && tstate->c_profilefunc)如果没有分析器/跟踪器,则使用正在运行的 else 分支进行分支):
static PyObject *
call_cfunc(DispatcherObject *self, PyObject *cfunc, PyObject *args, PyObject *kws, PyObject *locals)
{
PyCFunctionWithKeywords fn;
PyThreadState *tstate;
assert(PyCFunction_Check(cfunc));
assert(PyCFunction_GET_FLAGS(cfunc) == METH_VARARGS | METH_KEYWORDS);
fn = (PyCFunctionWithKeywords) PyCFunction_GET_FUNCTION(cfunc);
tstate = PyThreadState_GET();
if (tstate->use_tracing && tstate->c_profilefunc)
{
/*
* The following code requires some explaining:
*
* We want the jit-compiled function to be visible to the profiler, so we
* need to synthesize a frame for it.
* The PyFrame_New() constructor doesn't do anything with the 'locals' value if the 'code's
* 'CO_NEWLOCALS' flag is set (which is always the case nowadays).
* So, to get local variables into the frame, we have to manually set the 'f_locals'
* member, then call `PyFrame_LocalsToFast`, where a subsequent call to the `frame.f_locals`
* property (by virtue of the `frame_getlocals` function in frameobject.c) will find them.
*/
PyCodeObject *code = (PyCodeObject*)PyObject_GetAttrString((PyObject*)self, "__code__");
PyObject *globals = PyDict_New();
PyObject *builtins = PyEval_GetBuiltins();
PyFrameObject *frame = NULL;
PyObject *result = NULL;
if (!code) {
PyErr_Format(PyExc_RuntimeError, "No __code__ attribute found.");
goto error;
}
/* Populate builtins, which is required by some JITted functions */
if (PyDict_SetItemString(globals, "__builtins__", builtins)) {
goto error;
}
frame = PyFrame_New(tstate, code, globals, NULL);
if (frame == NULL) {
goto error;
}
/* Populate the 'fast locals' in `frame` */
Py_XDECREF(frame->f_locals);
frame->f_locals = locals;
Py_XINCREF(frame->f_locals);
PyFrame_LocalsToFast(frame, 0);
tstate->frame = frame;
C_TRACE(result, fn(PyCFunction_GET_SELF(cfunc), args, kws));
tstate->frame = frame->f_back;
error:
Py_XDECREF(frame);
Py_XDECREF(globals);
Py_XDECREF(code);
return result;
}
else
return fn(PyCFunction_GET_SELF(cfunc), args, kws);
}
我假设这个额外的代码(如果分析器正在运行)会在您进行 cProfile 时减慢函数的速度。
有点不幸的是,当您运行分析器时,numba 函数会增加如此多的开销,但如果您在 numba 函数中做任何实质性的事情,那么减速实际上几乎可以忽略不计。
如果您还要在 numba 函数中移动 for 循环,那就更是如此。
如果您注意到 numba 函数(运行或不运行探查器)花费太多时间,那么您可能调用它的频率太高了。然后你应该检查你是否真的可以将循环移动到 numba 函数内或将包含循环的代码包装在另一个 numba 函数中。
注意:所有这些都是(有点)推测,我实际上并没有使用调试符号构建 numba 并分析 C 代码以防分析器正在运行。然而,如果有一个分析器正在运行,那么操作的数量使得这看起来非常合理。所有这些都假设 numba 0.39,不确定这是否也适用于过去的版本。
关于python - cProfile 在调用 numba jit 函数时会增加大量开销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51384157/
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
我正在尝试用ruby中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent
这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。