A new ExpressionRuntime (Lark grammar compile) per evaluated expression makes evaluation ~5x slower

未关闭 适合新手
#178 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

@florian-burelli 已经在做这个了。

开始于 2026年10月7日。

  • #182 来自 @florian-burelli —— 未关闭

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
86/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
python

调研方向

从 src/data_factory_testing_framework/models/_data_factory_element.py 开始,检查 ExpressionRuntime 的创建方式,然后阅读 ExpressionRuntime.init 以及 expression_transformer.py 中的语法编译。复现 issue 中的计时比较,并运行项目的 pipeline 测试。当评估能够复用 runtime 设置、无需为每个表达式进行语法编译,同时保留现有行为时,即表示完成。

由索引模型根据 Issue 内容生成。

描述

Every DataFactoryElement.evaluate creates a new ExpressionRuntime, and every ExpressionRuntime compiles the Lark grammar of the expression language again. Evaluating one expression costs about 5x what the evaluation itself takes.

Environment: data-factory-testing-framework 1.4.2 (also present on main at 11b9f27), Python 3.12.13, .NET 10.0.12, Linux.

Repro

import time

from data_factory_testing_framework._expression_runtime.expression_runtime import ExpressionRuntime
from data_factory_testing_framework.models import DataFactoryElement
from data_factory_testing_framework.state import PipelineRunState

state = PipelineRunState([], [])
element = DataFactoryElement("@concat('a', 'b')")

start = time.perf_counter()
for _ in range(50):
    element.evaluate(state)
per_call = (time.perf_counter() - start) / 50

runtime = ExpressionRuntime()
start = time.perf_counter()
for _ in range(50):
    runtime.evaluate("@concat('a', 'b')", state)
shared = (time.perf_counter() - start) / 50

start = time.perf_counter()
ExpressionRuntime()
construct = time.perf_counter() - start

print(f"DataFactoryElement.evaluate: {per_call * 1000:.1f} ms per expression")
print(f"shared ExpressionRuntime:    {shared * 1000:.1f} ms per expression")
print(f"ExpressionRuntime():         {construct * 1000:.1f} ms")

Output

DataFactoryElement.evaluate: 48.0 ms per expression
shared ExpressionRuntime:    9.8 ms per expression
ExpressionRuntime():         27.9 ms

On a real suite (about 30 pipeline tests, each run evaluating dozens of expressions) this was 109 s; sharing one runtime brought it to 11 s.

Cause

_data_factory_element.py#L29 builds a runtime per call:

expression_runtime = ExpressionRuntime()

and ExpressionRuntime.__init__ builds an ExpressionTransformer, which compiles the grammar (expression_transformer.py#L108).

Suggested fix: create the runtime once (module-level or a cached factory) and reuse it; it holds no per-evaluation state. As a workaround we patch data_factory_testing_framework.models._data_factory_element.ExpressionRuntime to return a shared instance.

主要语言
Python
星标
135
派生
44
平均合并
6 天 20 小时
30 天内合并 PR
2

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 没有贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

microsoft/data-factory-testing-framework 的其他 Issue

查看 microsoft/data-factory-testing-framework 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。