首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用从循环中的代码片段提取的函数避免代码冗余/计算开销。

使用从循环中的代码片段提取的函数避免代码冗余/计算开销。
EN

Stack Overflow用户
提问于 2021-02-08 12:28:58
回答 1查看 70关注 0票数 2

我有一个循环,循环数天和一个金融时间序列的离散时隙,我的策略的一些代码就在里面。我将这个内部代码提取到一个独立的函数中,以便能够在特定情况下使用它进行测试,直到稍后才发现这个操作大大增加了这个循环的总计算时间。这是合理的,长函数签名,调用,(堆栈内存?)所有这些都会带来一些开销。

代码语言:javascript
复制
# Fast, but cannot use my strategy for specific instances:
for d in data:
    # my strategy code

# Flexible but really slow
def my_strategy(**params):
    # my strategy code
f = partial(my_strategy, **params)
for d in data:
    f(d)

现在,我的问题是:是否有一种方法可以同时保留中的设置、独立函数和具有循环和实际代码的函数,而不需要显式冗余?我需要两者兼得。

我已经用inspect.getsource(my_function)做了实验,并包装了一份外部函数的副本,然后使用eval,但是5分钟后,我觉得自己像个白痴,感觉一点也不对。

做这件事的最佳做法是什么?如果我重复代码,我必须确保如果我修改一个版本,另一个版本总是同步的。我不喜欢这样。我想要有效地反映这一点。

正如您可能已经想到的那样,有一个选项可以是:将代码留在循环中,并在需要时将特定的情况包装在数组中,并将其提供给循环。嗯,我不能这样做,主要是因为我需要对内部代码执行有一个定时的控制(正在将经过回传测试的策略移植到实时)。在这里,我只是寻找一些快速的技巧,以反映优雅的代码,如果有任何。

编辑

好的,为了进一步测试这一点,我实现了我刚才提到的可怕的攻击,并让它与exec一起工作。由于这一点,我现在可以保证所使用的代码完全相同。不过,观测到的时差是一样的。包含代码的循环大约占用函数调用循环所需时间的一半。

代码语言:javascript
复制
# horrible hack, please forgive me
def extract_strategy_function():
    # Start
    source_code = inspect.getsource(fastest_compute_trades)
    # Cutting the code snippet
    source_code = source_code.split('[safe_start - 1:]:', 1)[1].rsplit("if s['pos_open']:", 1)[0]
    # Needs re-indentation so the parser doesn't complain
    source_code = reindent(source_code, -2)
    function_name = 'single_apply_strategy'  # internal, no-one will see this anyway
    function_string = f"""
    def {function_name}(
            # INDICATORS (non mutable)
            i_time, close_price, r2, ma1, ma2, rsi, upper, lower,
            # STATE VARIABLES, TX HISTORY (mutable, 2 dictionaries and 1 list of dicts)
            s, gs, transactions,
            # CONSTANT PARAMETERS (non mutable)
            min_r2, macd_threshold, rsi_bound, waiting_slots, stop_loss,
            take_profit, trail_profit, double_down, dd_qty, commission_fee,
            # Day ID, useful when back-testing/grid-searching, left at the end so it can default to 0
            i_day=0
    ):
    {source_code}
    """.strip()
    # Evaluate it
    exec(function_string)  # Now in locals
    return locals()[function_name]
    
def slow(...):
    
    ...
    
    apply_strategy = partial(extract_strategy_function(), 
        **params, commission_fee=commission_fee, rsi_bound=rsi_bound)
   
    for i_day, day in enumerate(data):
        for i_time, close_price, r2, ma1, ma2, rsi, upper, lower, in list(enumerate(day))[safe_start - 1:]:
            apply_strategy(i_time, close_price, r2, ma1, ma2, rsi, upper, lower, 
                day_state, global_state, transactions, i_day=i_day)

        if day_state['pos_open']:
            ...
    
    ...
    
def fast(..., 
    #some extra parameters are now unpacked here, 
    #since all code is here they are now needed here
):
    ...
    
    for i_day, day in enumerate(data):
        for i_time, close_price, r2, ma1, ma2, rsi, upper, lower, in list(enumerate(day))[safe_start - 1:]:
            # actual code contained in single_apply_strategy written here, the whole strategy (one timestep)

        if day_state['pos_open']:
            ...
            
    ...

有什么建议吗?

附注:不用说,这两个设置的输出完全相同。

EN

回答 1

Stack Overflow用户

发布于 2021-02-08 14:07:14

函数调用引起的任何开销很可能可以忽略不计。使用您的功能,在需要的情况下,通过“手动插入”您的功能来衡量可能的改进。

如果您需要这样的性能,Python可能不是最好的选择,在这种情况下,我建议使用C++。您需要一个语言特性,它称为内联函数:https://www.geeksforgeeks.org/inline-functions-cpp/

有关Python和内联的更多信息:Python equivalence to inline functions or macros

无论如何,我认为你在这个方向上的努力不会有任何改善。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66101653

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档