本文介绍了朱莉娅:将代码注入函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将代码注入到函数中.为了具体起见,请考虑一个简单的模拟器:

I would like to inject code into a function. For concreteness, consider a simple simulater:

function simulation(A, x)
    for t in 1:1000
        z = randn(3)
        x = A*x + z
    end
end

有时候我想每十个时间步记录一次x的值,有时每20个时间步记录一次z的值,有时我不想记录任何值.当然,我可以将一些标志作为函数的参数,并包含一些if-else语句.但是我想保持仿真代码干净,只注入一段代码,例如

Sometimes I would like to record the values of x every ten time-steps, sometimes the values of z every 20 time-steps, and sometimes I don't want to record any values. I could, of course, put some flags as arguments to the function, and have some if-else statements. But I would like to rather keep the simulation code clean, and only inject a piece of code like

if t%10 == 0
    append!(rec_z, z)
end

在需要时在函数的特定位置添加

.为此,我想编写一个宏,以便监视特定的值

into particular places of the function whenever I need it. For that, I'd like to write a macro such that monitoring a particular value becomes

@monitor(:z, 10)
simulation(A, x)

Julia的元编程功能是否可能?

Is that possible with Julia's Metaprogramming capabilities?

推荐答案

否,您不能使用元编程将代码注入到已编写的函数中.元编程只能做一些事情,您可以直接在自己编写宏的确切位置直接编写自己.这意味着这样的语句:

No, you cannot use metaprogramming to inject code into an already-written function. Metaprogramming can only do things that you could directly write yourself at precisely the location where the macro itself is written. That means that a statement like:

@monitor(:z, 10); simulation(A, x)

甚至无法修改simulation(A, x)函数调用.它只能扩展为在simulation调用之前运行的一些常规Julia代码.您也许可以将模拟函数调用作为宏的参数包括在内,例如@monitor(:z, 10, simulation(A, x)),但是现在宏可以做的就是更改函数调用本身.它仍然无法返回"并将新代码添加到已编写的函数中.

cannot even modify the simulation(A, x) function call. It can only expand out to some normal Julia code that runs before simulation is called. You could, perhaps, include the simulation function call as an argument to the macro, e.g., @monitor(:z, 10, simulation(A, x)), but now all the macro can do is change the function call itself. It still cannot "go back" and add new code to a function that was already written.

但是,您可以精心设计一个宏,该宏采用函数定义主体并对其进行修改以添加您的调试代码,例如,

You could, however, carefully and meticulously craft a macro that takes the function definition body and modifies it to add your debug code, e.g.,

@monitor(:z, 10, function simulation(A, x)
    for t in 1:1000
        # ...
    end
end)

但是现在您必须在遍历函数体内代码的宏中编写 code ,并将调试语句插入正确的位置.这不是一件容易的事.而且,以健壮的方式编写代码甚至在修改实际仿真代码的那一刻都不会中断的情况下更加困难.

But now you must write code in the macro that traverses the code in the function body, and injects your debug statement at the correct place. This is not an easy task. And it's even harder to write in a robust manner that wouldn't break the moment you modified your actual simulation code.

遍历代码并插入代码对于您自己使用编辑器来说是一件容易得多的任务.调试语句的常见习惯是使用单行代码,如下所示:

Traversing code and inserting it is a much easier task for you to do yourself with an editor. A common idiom for debugging statements is to use a one-liner, like this:

const debug = false
function simulation (A, x)
    for t in 1:1000
        z = rand(3)
        x = A*x + z
        debug && t%10==0 && append!(rec_z, z)
    end
end

真正的酷点在于,通过将debug标记为常量,Julia能够在false时完全优化调试代码,甚至不会出现在生成的代码中!因此,当您不进行调试时,没有任何开销.但是,这的确意味着您必须重新启动Julia(或重新加载它所在的模块)才能更改debug标志.即使debug未被标记为const,我也无法测量此简单循环的任何开销.而且可能的是,您的循环将比这更复杂.因此,在实际检查它是否起作用之前,请不要担心性能.

What's really cool here is that by marking debug as constant, Julia is able to completely optimize away the debugging code when it's false — it doesn't even appear in the generated code! So there is no overhead when you're not debugging. It does mean, however, that you have to restart Julia (or reload the module it's in) for you to change the debug flag. Even when debug isn't marked as const, I cannot measure any overhead for this simple loop. And chances are, your loop will be more complicated than this one. So don't worry about performance here until you actually double-check that it's having an effect.

这篇关于朱莉娅:将代码注入函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-06 01:32