A new ExpressionRuntime (Lark grammar compile) per evaluated expression makes evaluation ~5x slower
评估
- 难度
- 2/5
- 预计耗时
- 1-3 小时
- 新手友好度
- 86/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- python
- 领域
- performance, testing
调研方向
从 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
环境准备
在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 没有贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
microsoft/data-factory-testing-framework 的其他 Issue
-
item() equal to 0 raises StateIterationItemNotSetError (falsy item treated as unset)可能已有人在做 @florian-burelli 于 26 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 88/100
-
IfCondition evaluates the expressions of the branch not taken (case-sensitive "activities" check)可能已有人在做 @florian-burelli 于 26 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 84/100
-
DataFactoryTestingFrameworkExpressionsEvaluator adds status property even if None is set.可能已有人在做 @LeonardHd 于 461 天前认领。 未关闭bug
难度 2/5 1-3 小时 新手友好度 68/100
-
难度 3/5 1-2 天 新手友好度 35/100
-
难度 4/5 3-5 天 新手友好度 35/100
查看 microsoft/data-factory-testing-framework 的全部 Issue
相似的 Issue
-
cost:cheap practicality:seen-in-the-wild severity:medium
难度 2/5 1-3 小时 新手友好度 72/100
fairagro/m4.2_advanced_middleware_api#620 ·
维护者通常 1 天内回复
-
area:security effort:S priority:P2 provider:local-libvirt status:ready type:docs
难度 2/5 1-3 小时 新手友好度 75/100
randomparity/kdive#3495 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 82/100
microsoft/markitdown#2820 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 2 天内回复