celestialflow 3.2.8__tar.gz → 3.2.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {celestialflow-3.2.8/src/celestialflow.egg-info → celestialflow-3.2.9}/PKG-INFO +67 -70
- {celestialflow-3.2.8 → celestialflow-3.2.9}/README.md +66 -69
- {celestialflow-3.2.8 → celestialflow-3.2.9}/pyproject.toml +1 -1
- celestialflow-3.2.9/src/celestialflow/benchmark/util_benchmark.py +129 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/benchmark/util_clone.py +7 -10
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/graph/core_graph.py +139 -169
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/graph/core_structure.py +24 -47
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/graph/util_estimators.py +1 -1
- celestialflow-3.2.8/src/celestialflow/graph/util_graph.py → celestialflow-3.2.9/src/celestialflow/graph/util_order_graph.py +56 -32
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/graph/util_serialize.py +149 -150
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/observability/core_report.py +25 -25
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/observability/util_types.py +1 -1
- celestialflow-3.2.9/src/celestialflow/persistence/__init__.py +31 -0
- celestialflow-3.2.8/src/celestialflow/persistence/core_fallback.py → celestialflow-3.2.9/src/celestialflow/persistence/core_lifecycle.py +27 -55
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/persistence/core_log.py +19 -21
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/persistence/core_scope.py +41 -41
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/persistence/util_sqlite.py +0 -30
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/runtime/util_errors.py +207 -207
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/runtime/util_event.py +0 -1
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/stage/core_dispatch.py +8 -4
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/stage/core_executor.py +652 -692
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/stage/core_stage.py +3 -45
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/stage/core_stages.py +6 -16
- {celestialflow-3.2.8 → celestialflow-3.2.9/src/celestialflow.egg-info}/PKG-INFO +67 -70
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow.egg-info/SOURCES.txt +2 -2
- celestialflow-3.2.8/src/celestialflow/benchmark/util_benchmark.py +0 -142
- celestialflow-3.2.8/src/celestialflow/persistence/__init__.py +0 -31
- {celestialflow-3.2.8 → celestialflow-3.2.9}/LICENSE +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/setup.cfg +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/__init__.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/benchmark/__init__.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/funnel/__init__.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/funnel/core_inlet.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/funnel/core_spout.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/funnel/util_count.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/graph/__init__.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/observability/__init__.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/observability/core_observer.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/persistence/util_payload.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/runtime/__init__.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/runtime/core_envelope.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/runtime/core_metrics.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/runtime/core_queue.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/runtime/util_config.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/runtime/util_constant.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/runtime/util_estimators.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/runtime/util_format.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/runtime/util_hash.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/runtime/util_types.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/stage/__init__.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/stage/util_callable.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow/stage/util_types.py +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow.egg-info/dependency_links.txt +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow.egg-info/requires.txt +0 -0
- {celestialflow-3.2.8 → celestialflow-3.2.9}/src/celestialflow.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: celestialflow
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.9
|
|
4
4
|
Summary: A flexible GRAPH-based task orchestration framework.
|
|
5
5
|
Author-email: Mr-xiaotian <mingxiaomingtian@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -258,125 +258,122 @@ flowchart TD
|
|
|
258
258
|
## 文件结构(File Structure)
|
|
259
259
|
|
|
260
260
|
```
|
|
261
|
-
📁 CelestialFlow (
|
|
262
|
-
📁 bench (296KB
|
|
261
|
+
📁 CelestialFlow (588MB 419KB 930B)
|
|
262
|
+
📁 bench (296KB 806B)
|
|
263
263
|
📁 [1项排除的目录] (194KB 222B)
|
|
264
264
|
🐍 bench_datastructures.py (6KB 690B)
|
|
265
|
-
🐍 bench_execution_mode.py (2KB
|
|
265
|
+
🐍 bench_execution_mode.py (2KB 707B)
|
|
266
266
|
🐍 bench_futures_memory.py (2KB 269B)
|
|
267
|
-
🐍 bench_gil_vs_nogil.py (10KB
|
|
267
|
+
🐍 bench_gil_vs_nogil.py (10KB 121B)
|
|
268
268
|
🐍 bench_graph_mode.py (7KB 450B)
|
|
269
269
|
🐍 bench_hash.py (7KB 67B)
|
|
270
270
|
🐍 bench_hash_container.py (3KB 1009B)
|
|
271
271
|
🐍 bench_hash_memory.py (3KB 642B)
|
|
272
|
-
🐍 bench_http_grpc.py (2KB
|
|
272
|
+
🐍 bench_http_grpc.py (2KB 521B)
|
|
273
273
|
🐍 bench_ipc_queue.py (7KB 104B)
|
|
274
274
|
🐍 bench_lock_overhead.py (9KB 421B)
|
|
275
275
|
🐍 bench_mpqueue_vs_shared_memory.py (13KB 127B)
|
|
276
276
|
🐍 bench_observer.py (7KB 860B)
|
|
277
|
-
🐍 bench_persistence_spout.py (4KB
|
|
277
|
+
🐍 bench_persistence_spout.py (4KB 340B)
|
|
278
278
|
🐍 bench_queue.py (5KB 857B)
|
|
279
279
|
🐍 bench_requests.py (6KB 813B)
|
|
280
280
|
🐍 bench_tqdm.py (1KB 235B)
|
|
281
281
|
🐍 bench_utils.py (543B)
|
|
282
|
-
📁 demo (
|
|
282
|
+
📁 demo (145KB 1012B)
|
|
283
283
|
📁 [1项排除的目录] (100KB 9B)
|
|
284
284
|
🐍 demo_executor.py (1KB 495B)
|
|
285
285
|
🐍 demo_funnel.py (2KB 289B)
|
|
286
|
-
🐍 demo_graph.py (3KB
|
|
287
|
-
🐍 demo_network.py (3KB
|
|
286
|
+
🐍 demo_graph.py (3KB 227B)
|
|
287
|
+
🐍 demo_network.py (3KB 729B)
|
|
288
288
|
🐍 demo_observer.py (4KB 270B)
|
|
289
|
-
🐍 demo_redis.py (9KB
|
|
290
|
-
🐍 demo_stages.py (4KB
|
|
291
|
-
🐍 demo_structure.py (
|
|
289
|
+
🐍 demo_redis.py (9KB 81B)
|
|
290
|
+
🐍 demo_stages.py (4KB 219B)
|
|
291
|
+
🐍 demo_structure.py (11KB 593B)
|
|
292
292
|
🐍 demo_utils.py (6KB 148B)
|
|
293
|
-
📁 dist (
|
|
293
|
+
📁 dist (302KB 861B)
|
|
294
294
|
❓ .gitignore (1B)
|
|
295
295
|
❓ celestialflow-3.2.7-py3-none-any.whl (79KB 235B)
|
|
296
296
|
📦 celestialflow-3.2.7.tar.gz (67KB 836B)
|
|
297
|
-
|
|
297
|
+
❓ celestialflow-3.2.8-py3-none-any.whl (83KB 244B)
|
|
298
|
+
📦 celestialflow-3.2.8.tar.gz (72KB 569B)
|
|
299
|
+
📁 docs (1MB 756KB 830B)
|
|
298
300
|
📁 en[已折叠] (568KB 991B)
|
|
299
301
|
📁 ja[已折叠] (642KB 383B)
|
|
300
|
-
📁 zh-CN[已折叠] (
|
|
301
|
-
📁 experiments (2KB
|
|
302
|
-
🐍 experiment_networkx.py (1KB
|
|
302
|
+
📁 zh-CN[已折叠] (569KB 480B)
|
|
303
|
+
📁 experiments (2KB 1021B)
|
|
304
|
+
🐍 experiment_networkx.py (1KB 884B)
|
|
303
305
|
🐍 experiment_tqdm.py (1KB 137B)
|
|
304
306
|
📁 img (5MB 871KB 242B)
|
|
305
307
|
📷 file_structure.svg (4MB 918KB 1000B)
|
|
306
308
|
📷 logo(old).png (836KB 542B)
|
|
307
309
|
📷 logo.png (122KB 747B)
|
|
308
310
|
📷 scc_condensation.svg (17KB 1B)
|
|
309
|
-
📁 src (1MB
|
|
310
|
-
📁 celestialflow[已折叠] (1MB
|
|
311
|
-
📁 celestialflow.egg-info[已折叠] (
|
|
312
|
-
📁 tests (4MB
|
|
313
|
-
📁 benchmark[已折叠] (
|
|
311
|
+
📁 src (1MB 873KB 44B)
|
|
312
|
+
📁 celestialflow[已折叠] (1MB 852KB 902B)
|
|
313
|
+
📁 celestialflow.egg-info[已折叠] (20KB 166B)
|
|
314
|
+
📁 tests (4MB 170KB 251B)
|
|
315
|
+
📁 benchmark[已折叠] (39KB 852B)
|
|
314
316
|
📁 funnel[已折叠] (96KB 363B)
|
|
315
|
-
📁 graph[已折叠] (
|
|
316
|
-
📁 observability[已折叠] (189KB
|
|
317
|
-
📁 persistence[已折叠] (
|
|
318
|
-
📁 runtime[已折叠] (1MB 295KB
|
|
319
|
-
📁 stage[已折叠] (
|
|
317
|
+
📁 graph[已折叠] (724KB 404B)
|
|
318
|
+
📁 observability[已折叠] (189KB 230B)
|
|
319
|
+
📁 persistence[已折叠] (387KB 877B)
|
|
320
|
+
📁 runtime[已折叠] (1MB 295KB 264B)
|
|
321
|
+
📁 stage[已折叠] (381KB 203B)
|
|
320
322
|
📁 utils[已折叠] (639KB 527B)
|
|
321
323
|
📁 [1项排除的目录] (487KB 589B)
|
|
322
324
|
🐍 conftest.py (1KB 38B)
|
|
323
325
|
🐍 __init__.py (0B)
|
|
324
|
-
📁 [12项排除的目录] (573MB
|
|
326
|
+
📁 [12项排除的目录] (573MB 949KB 913B)
|
|
325
327
|
❓ .env (468B)
|
|
326
|
-
❓ .gitignore (1KB
|
|
327
|
-
📝 AGENTS.md (1KB
|
|
328
|
+
❓ .gitignore (1KB 315B)
|
|
329
|
+
📝 AGENTS.md (1KB 434B)
|
|
328
330
|
❓ LICENSE (1KB 65B)
|
|
329
331
|
❓ Makefile (155B)
|
|
330
332
|
⚙️ pyproject.toml (2KB 668B)
|
|
331
|
-
📝 README.md (
|
|
332
|
-
🔒 uv.lock (
|
|
333
|
+
📝 README.md (17KB 465B)
|
|
334
|
+
🔒 uv.lock (121KB 572B)
|
|
333
335
|
```
|
|
334
336
|
<p align="center">
|
|
335
|
-
<em>celestial-flow 3.2.
|
|
337
|
+
<em>celestial-flow 3.2.9</em>
|
|
336
338
|
</p>
|
|
337
339
|
|
|
338
340
|
(该视图由我的另一个项目[CelestialVault](https://github.com/Mr-xiaotian/CelestialVault)中inst_file.FileTree.print_tree()生成。转换为图片则借助[Carbon](https://carbon.now.sh)。)
|
|
339
341
|
|
|
340
342
|
## 版本日志(Version Log)
|
|
341
|
-
- 3.2.
|
|
343
|
+
- 3.2.9
|
|
342
344
|
- feat:
|
|
343
|
-
- [IMPORTANT]
|
|
344
|
-
- 根据 `bench_graph_mode.py` 最新测试, 在I/O密集型任务中, `serial`+`async`(6.05s),比 `serial`+`serial`(69.04s)快 **11.4x**
|
|
345
|
-
- 在 `core_structure` 中添加报错校验
|
|
346
|
-
- 不再允许设置 `execution_mode=async` 时调用 `TashExecutor.start`(如今的`TashExecutor.run`), 只能调用 `TashExecutor.run_async`
|
|
347
|
-
- 另外调用 `TashExecutor.run_async` 时也会进行模式检查, 不是 `execution_mode=async` 就会抛出异常
|
|
348
|
-
- 在 `BaseObserver` 中添加 `observer_error`, 用于处理 `BaseObserver.on_*` 函数的报错
|
|
349
|
-
- 在 `TaskGraph._finish_start_graph` `TaskExecutor._finish_start` 中对所有执行步骤进行 `try-except`, 以使收尾步骤尽量全部完成
|
|
350
|
-
- 添加 `core_scope`, 用于独立控制 `funnel` 的生命周期, 并用于 `TaskGraph.run/run_async` `TaskExecutor.run/run_async`
|
|
351
|
-
- refactor:
|
|
352
|
-
- [IMPORTANT] 原 `TaskGraph.start_graph/start_graph_async` `TaskExecutor.start/start_async` 已被重命名为 `TaskGraph.run/run_async` `TaskExecutor.run/run_async`
|
|
345
|
+
- [IMPORTANT] 移除 `stage` 中 `stage_mode`,并添加 `graph_mode`
|
|
353
346
|
- 破坏性更新
|
|
354
|
-
-
|
|
355
|
-
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
-
|
|
360
|
-
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
-
|
|
364
|
-
-
|
|
365
|
-
-
|
|
366
|
-
-
|
|
367
|
-
|
|
368
|
-
-
|
|
369
|
-
-
|
|
370
|
-
-
|
|
371
|
-
-
|
|
347
|
+
- `stage_mode` 可以细粒度的控制每个 `TaskStage` 在图中的模式,但经过多年使用,我认为这种细粒度的控制并无必要,反而无谓的增加理解成本
|
|
348
|
+
- `graph_mode` 则提供了更粗粒度的控制,用于统一控制所有 `TaskStage` 在图中是串行/多线程/并发运行,适用于大多数场景
|
|
349
|
+
- 同时完善了 `graph_mode`(serial/thread/async) * `execution_mode`(serial/thread/async) 总共 9 种组合模式
|
|
350
|
+
- 移除 `schedule_mode`
|
|
351
|
+
- 破坏性更新
|
|
352
|
+
- 这个模式带来了许多复杂度,但没有与原先的 `stage_mode / execution_mode` 产生明显的组合优势
|
|
353
|
+
- 在 `get_graph_analysis` 中添加 `graph_mode`
|
|
354
|
+
- 这个函数主要用于给web端提供信息
|
|
355
|
+
- web端代码已经同步修改
|
|
356
|
+
- 添加新的 `warning` 项,当图不是 dag 且 `graph_mode=serial` 时触发
|
|
357
|
+
- 移除 `task_executor` 中的参数 `persist_result`
|
|
358
|
+
- 这是为了简化代码逻辑,同时也使所有任务的最终状态(包括:成功/失败/未执行)都能被统一存储
|
|
359
|
+
- 将 `task.retry` 事件降级,不再申请单独事件ID,不再在 `lifecycle` 中留痕
|
|
360
|
+
- reafactor:
|
|
361
|
+
- 合并 `benchmark` 相关函数对 sync 与 async 两种模式的执行
|
|
362
|
+
- 性能无差异,代码好看一些
|
|
363
|
+
- 将原本的 `fallback` 改名为 `lifecycle`
|
|
364
|
+
- 早在重构原本的 `fail` 时就想起个更恰当的名字,这个版本才实现
|
|
365
|
+
- 将 `graph.source_lists` 改为 `graph.source_names`
|
|
366
|
+
- `graph.source_lists` 直接存储节点的引用,而 `graph.source_names` 存储节点的名称
|
|
367
|
+
- 所有的 `log` / `lifecycle` 文件统一改名为 `flow_log` / `flow_lifecycle`
|
|
368
|
+
- 删除 `graph` 中的 `out_edges` `in_edges`
|
|
369
|
+
- 现在由 `OrderGraph` 负责管理边关系
|
|
370
|
+
- 在 `tarjan_scc` 中使用 DFS 取代原先的递归逻辑
|
|
371
|
+
- 将 `util_graph` 改名为 `util_order_graph`
|
|
372
372
|
- fix:
|
|
373
|
-
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
-
|
|
377
|
-
- 修复 `TaskGraph` 中部分 `get_*` 方法依赖 `_build_analysis` 的产物, 但 `_build_analysis` 未执行导致的问题
|
|
378
|
-
- 修复 `TaskMetrics` 中 `get_counts` 与 `is_tasks_finished` 中可能导致死锁的问题
|
|
379
|
-
- 修复 `TaskReporter` 中 `stop` 里进行的最后一次 `_refresh_all` 没有错误捕捉, 导致后续收尾未完成的问题
|
|
373
|
+
- 修复最后一次 report 无法正常上传的问题
|
|
374
|
+
- 修复 `graph.run` / `graph.run_async` 中 `is_put_signal` 参数没有生效的问题
|
|
375
|
+
- chore:
|
|
376
|
+
- 更新文档
|
|
380
377
|
|
|
381
378
|
更多过往日志可看:
|
|
382
379
|
|
|
@@ -239,125 +239,122 @@ flowchart TD
|
|
|
239
239
|
## 文件结构(File Structure)
|
|
240
240
|
|
|
241
241
|
```
|
|
242
|
-
📁 CelestialFlow (
|
|
243
|
-
📁 bench (296KB
|
|
242
|
+
📁 CelestialFlow (588MB 419KB 930B)
|
|
243
|
+
📁 bench (296KB 806B)
|
|
244
244
|
📁 [1项排除的目录] (194KB 222B)
|
|
245
245
|
🐍 bench_datastructures.py (6KB 690B)
|
|
246
|
-
🐍 bench_execution_mode.py (2KB
|
|
246
|
+
🐍 bench_execution_mode.py (2KB 707B)
|
|
247
247
|
🐍 bench_futures_memory.py (2KB 269B)
|
|
248
|
-
🐍 bench_gil_vs_nogil.py (10KB
|
|
248
|
+
🐍 bench_gil_vs_nogil.py (10KB 121B)
|
|
249
249
|
🐍 bench_graph_mode.py (7KB 450B)
|
|
250
250
|
🐍 bench_hash.py (7KB 67B)
|
|
251
251
|
🐍 bench_hash_container.py (3KB 1009B)
|
|
252
252
|
🐍 bench_hash_memory.py (3KB 642B)
|
|
253
|
-
🐍 bench_http_grpc.py (2KB
|
|
253
|
+
🐍 bench_http_grpc.py (2KB 521B)
|
|
254
254
|
🐍 bench_ipc_queue.py (7KB 104B)
|
|
255
255
|
🐍 bench_lock_overhead.py (9KB 421B)
|
|
256
256
|
🐍 bench_mpqueue_vs_shared_memory.py (13KB 127B)
|
|
257
257
|
🐍 bench_observer.py (7KB 860B)
|
|
258
|
-
🐍 bench_persistence_spout.py (4KB
|
|
258
|
+
🐍 bench_persistence_spout.py (4KB 340B)
|
|
259
259
|
🐍 bench_queue.py (5KB 857B)
|
|
260
260
|
🐍 bench_requests.py (6KB 813B)
|
|
261
261
|
🐍 bench_tqdm.py (1KB 235B)
|
|
262
262
|
🐍 bench_utils.py (543B)
|
|
263
|
-
📁 demo (
|
|
263
|
+
📁 demo (145KB 1012B)
|
|
264
264
|
📁 [1项排除的目录] (100KB 9B)
|
|
265
265
|
🐍 demo_executor.py (1KB 495B)
|
|
266
266
|
🐍 demo_funnel.py (2KB 289B)
|
|
267
|
-
🐍 demo_graph.py (3KB
|
|
268
|
-
🐍 demo_network.py (3KB
|
|
267
|
+
🐍 demo_graph.py (3KB 227B)
|
|
268
|
+
🐍 demo_network.py (3KB 729B)
|
|
269
269
|
🐍 demo_observer.py (4KB 270B)
|
|
270
|
-
🐍 demo_redis.py (9KB
|
|
271
|
-
🐍 demo_stages.py (4KB
|
|
272
|
-
🐍 demo_structure.py (
|
|
270
|
+
🐍 demo_redis.py (9KB 81B)
|
|
271
|
+
🐍 demo_stages.py (4KB 219B)
|
|
272
|
+
🐍 demo_structure.py (11KB 593B)
|
|
273
273
|
🐍 demo_utils.py (6KB 148B)
|
|
274
|
-
📁 dist (
|
|
274
|
+
📁 dist (302KB 861B)
|
|
275
275
|
❓ .gitignore (1B)
|
|
276
276
|
❓ celestialflow-3.2.7-py3-none-any.whl (79KB 235B)
|
|
277
277
|
📦 celestialflow-3.2.7.tar.gz (67KB 836B)
|
|
278
|
-
|
|
278
|
+
❓ celestialflow-3.2.8-py3-none-any.whl (83KB 244B)
|
|
279
|
+
📦 celestialflow-3.2.8.tar.gz (72KB 569B)
|
|
280
|
+
📁 docs (1MB 756KB 830B)
|
|
279
281
|
📁 en[已折叠] (568KB 991B)
|
|
280
282
|
📁 ja[已折叠] (642KB 383B)
|
|
281
|
-
📁 zh-CN[已折叠] (
|
|
282
|
-
📁 experiments (2KB
|
|
283
|
-
🐍 experiment_networkx.py (1KB
|
|
283
|
+
📁 zh-CN[已折叠] (569KB 480B)
|
|
284
|
+
📁 experiments (2KB 1021B)
|
|
285
|
+
🐍 experiment_networkx.py (1KB 884B)
|
|
284
286
|
🐍 experiment_tqdm.py (1KB 137B)
|
|
285
287
|
📁 img (5MB 871KB 242B)
|
|
286
288
|
📷 file_structure.svg (4MB 918KB 1000B)
|
|
287
289
|
📷 logo(old).png (836KB 542B)
|
|
288
290
|
📷 logo.png (122KB 747B)
|
|
289
291
|
📷 scc_condensation.svg (17KB 1B)
|
|
290
|
-
📁 src (1MB
|
|
291
|
-
📁 celestialflow[已折叠] (1MB
|
|
292
|
-
📁 celestialflow.egg-info[已折叠] (
|
|
293
|
-
📁 tests (4MB
|
|
294
|
-
📁 benchmark[已折叠] (
|
|
292
|
+
📁 src (1MB 873KB 44B)
|
|
293
|
+
📁 celestialflow[已折叠] (1MB 852KB 902B)
|
|
294
|
+
📁 celestialflow.egg-info[已折叠] (20KB 166B)
|
|
295
|
+
📁 tests (4MB 170KB 251B)
|
|
296
|
+
📁 benchmark[已折叠] (39KB 852B)
|
|
295
297
|
📁 funnel[已折叠] (96KB 363B)
|
|
296
|
-
📁 graph[已折叠] (
|
|
297
|
-
📁 observability[已折叠] (189KB
|
|
298
|
-
📁 persistence[已折叠] (
|
|
299
|
-
📁 runtime[已折叠] (1MB 295KB
|
|
300
|
-
📁 stage[已折叠] (
|
|
298
|
+
📁 graph[已折叠] (724KB 404B)
|
|
299
|
+
📁 observability[已折叠] (189KB 230B)
|
|
300
|
+
📁 persistence[已折叠] (387KB 877B)
|
|
301
|
+
📁 runtime[已折叠] (1MB 295KB 264B)
|
|
302
|
+
📁 stage[已折叠] (381KB 203B)
|
|
301
303
|
📁 utils[已折叠] (639KB 527B)
|
|
302
304
|
📁 [1项排除的目录] (487KB 589B)
|
|
303
305
|
🐍 conftest.py (1KB 38B)
|
|
304
306
|
🐍 __init__.py (0B)
|
|
305
|
-
📁 [12项排除的目录] (573MB
|
|
307
|
+
📁 [12项排除的目录] (573MB 949KB 913B)
|
|
306
308
|
❓ .env (468B)
|
|
307
|
-
❓ .gitignore (1KB
|
|
308
|
-
📝 AGENTS.md (1KB
|
|
309
|
+
❓ .gitignore (1KB 315B)
|
|
310
|
+
📝 AGENTS.md (1KB 434B)
|
|
309
311
|
❓ LICENSE (1KB 65B)
|
|
310
312
|
❓ Makefile (155B)
|
|
311
313
|
⚙️ pyproject.toml (2KB 668B)
|
|
312
|
-
📝 README.md (
|
|
313
|
-
🔒 uv.lock (
|
|
314
|
+
📝 README.md (17KB 465B)
|
|
315
|
+
🔒 uv.lock (121KB 572B)
|
|
314
316
|
```
|
|
315
317
|
<p align="center">
|
|
316
|
-
<em>celestial-flow 3.2.
|
|
318
|
+
<em>celestial-flow 3.2.9</em>
|
|
317
319
|
</p>
|
|
318
320
|
|
|
319
321
|
(该视图由我的另一个项目[CelestialVault](https://github.com/Mr-xiaotian/CelestialVault)中inst_file.FileTree.print_tree()生成。转换为图片则借助[Carbon](https://carbon.now.sh)。)
|
|
320
322
|
|
|
321
323
|
## 版本日志(Version Log)
|
|
322
|
-
- 3.2.
|
|
324
|
+
- 3.2.9
|
|
323
325
|
- feat:
|
|
324
|
-
- [IMPORTANT]
|
|
325
|
-
- 根据 `bench_graph_mode.py` 最新测试, 在I/O密集型任务中, `serial`+`async`(6.05s),比 `serial`+`serial`(69.04s)快 **11.4x**
|
|
326
|
-
- 在 `core_structure` 中添加报错校验
|
|
327
|
-
- 不再允许设置 `execution_mode=async` 时调用 `TashExecutor.start`(如今的`TashExecutor.run`), 只能调用 `TashExecutor.run_async`
|
|
328
|
-
- 另外调用 `TashExecutor.run_async` 时也会进行模式检查, 不是 `execution_mode=async` 就会抛出异常
|
|
329
|
-
- 在 `BaseObserver` 中添加 `observer_error`, 用于处理 `BaseObserver.on_*` 函数的报错
|
|
330
|
-
- 在 `TaskGraph._finish_start_graph` `TaskExecutor._finish_start` 中对所有执行步骤进行 `try-except`, 以使收尾步骤尽量全部完成
|
|
331
|
-
- 添加 `core_scope`, 用于独立控制 `funnel` 的生命周期, 并用于 `TaskGraph.run/run_async` `TaskExecutor.run/run_async`
|
|
332
|
-
- refactor:
|
|
333
|
-
- [IMPORTANT] 原 `TaskGraph.start_graph/start_graph_async` `TaskExecutor.start/start_async` 已被重命名为 `TaskGraph.run/run_async` `TaskExecutor.run/run_async`
|
|
326
|
+
- [IMPORTANT] 移除 `stage` 中 `stage_mode`,并添加 `graph_mode`
|
|
334
327
|
- 破坏性更新
|
|
335
|
-
-
|
|
336
|
-
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
-
|
|
341
|
-
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
-
|
|
345
|
-
-
|
|
346
|
-
-
|
|
347
|
-
-
|
|
348
|
-
|
|
349
|
-
-
|
|
350
|
-
-
|
|
351
|
-
-
|
|
352
|
-
-
|
|
328
|
+
- `stage_mode` 可以细粒度的控制每个 `TaskStage` 在图中的模式,但经过多年使用,我认为这种细粒度的控制并无必要,反而无谓的增加理解成本
|
|
329
|
+
- `graph_mode` 则提供了更粗粒度的控制,用于统一控制所有 `TaskStage` 在图中是串行/多线程/并发运行,适用于大多数场景
|
|
330
|
+
- 同时完善了 `graph_mode`(serial/thread/async) * `execution_mode`(serial/thread/async) 总共 9 种组合模式
|
|
331
|
+
- 移除 `schedule_mode`
|
|
332
|
+
- 破坏性更新
|
|
333
|
+
- 这个模式带来了许多复杂度,但没有与原先的 `stage_mode / execution_mode` 产生明显的组合优势
|
|
334
|
+
- 在 `get_graph_analysis` 中添加 `graph_mode`
|
|
335
|
+
- 这个函数主要用于给web端提供信息
|
|
336
|
+
- web端代码已经同步修改
|
|
337
|
+
- 添加新的 `warning` 项,当图不是 dag 且 `graph_mode=serial` 时触发
|
|
338
|
+
- 移除 `task_executor` 中的参数 `persist_result`
|
|
339
|
+
- 这是为了简化代码逻辑,同时也使所有任务的最终状态(包括:成功/失败/未执行)都能被统一存储
|
|
340
|
+
- 将 `task.retry` 事件降级,不再申请单独事件ID,不再在 `lifecycle` 中留痕
|
|
341
|
+
- reafactor:
|
|
342
|
+
- 合并 `benchmark` 相关函数对 sync 与 async 两种模式的执行
|
|
343
|
+
- 性能无差异,代码好看一些
|
|
344
|
+
- 将原本的 `fallback` 改名为 `lifecycle`
|
|
345
|
+
- 早在重构原本的 `fail` 时就想起个更恰当的名字,这个版本才实现
|
|
346
|
+
- 将 `graph.source_lists` 改为 `graph.source_names`
|
|
347
|
+
- `graph.source_lists` 直接存储节点的引用,而 `graph.source_names` 存储节点的名称
|
|
348
|
+
- 所有的 `log` / `lifecycle` 文件统一改名为 `flow_log` / `flow_lifecycle`
|
|
349
|
+
- 删除 `graph` 中的 `out_edges` `in_edges`
|
|
350
|
+
- 现在由 `OrderGraph` 负责管理边关系
|
|
351
|
+
- 在 `tarjan_scc` 中使用 DFS 取代原先的递归逻辑
|
|
352
|
+
- 将 `util_graph` 改名为 `util_order_graph`
|
|
353
353
|
- fix:
|
|
354
|
-
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
-
|
|
358
|
-
- 修复 `TaskGraph` 中部分 `get_*` 方法依赖 `_build_analysis` 的产物, 但 `_build_analysis` 未执行导致的问题
|
|
359
|
-
- 修复 `TaskMetrics` 中 `get_counts` 与 `is_tasks_finished` 中可能导致死锁的问题
|
|
360
|
-
- 修复 `TaskReporter` 中 `stop` 里进行的最后一次 `_refresh_all` 没有错误捕捉, 导致后续收尾未完成的问题
|
|
354
|
+
- 修复最后一次 report 无法正常上传的问题
|
|
355
|
+
- 修复 `graph.run` / `graph.run_async` 中 `is_put_signal` 参数没有生效的问题
|
|
356
|
+
- chore:
|
|
357
|
+
- 更新文档
|
|
361
358
|
|
|
362
359
|
更多过往日志可看:
|
|
363
360
|
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# benchmark/util_benchmark.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import asyncio
|
|
5
|
+
import time
|
|
6
|
+
from collections.abc import Iterable, Mapping
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from ..graph import TaskGraph
|
|
10
|
+
from ..runtime.util_format import format_table
|
|
11
|
+
from ..stage import TaskExecutor
|
|
12
|
+
from .util_clone import clone_executor, clone_graph
|
|
13
|
+
|
|
14
|
+
type AnyTaskExecutor = TaskExecutor[Any, Any]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def benchmark_executor(
|
|
18
|
+
sync_executor: AnyTaskExecutor,
|
|
19
|
+
async_executor: AnyTaskExecutor,
|
|
20
|
+
task_source: Iterable[Any],
|
|
21
|
+
execution_modes: list[str] | None = None,
|
|
22
|
+
) -> dict[str, Any]:
|
|
23
|
+
"""
|
|
24
|
+
对执行器进行基准测试
|
|
25
|
+
|
|
26
|
+
:param sync_executor: 同步执行器模板(用于 serial/thread execution_mode)
|
|
27
|
+
:param async_executor: 异步执行器模板(用于 async execution_mode)
|
|
28
|
+
:param task_source: 任务源,用于生成任务列表
|
|
29
|
+
:param execution_modes: 执行模式列表,默认 ["serial", "thread", "async"]
|
|
30
|
+
:return: 包含测试结果的字典
|
|
31
|
+
"""
|
|
32
|
+
task_list: list[Any] = list(task_source)
|
|
33
|
+
execution_modes = execution_modes or ["serial", "thread", "async"]
|
|
34
|
+
|
|
35
|
+
use_time: list[list[float]] = []
|
|
36
|
+
for mode in execution_modes:
|
|
37
|
+
if mode == "async":
|
|
38
|
+
cloned_executor = clone_executor(async_executor)
|
|
39
|
+
else:
|
|
40
|
+
cloned_executor = clone_executor(sync_executor)
|
|
41
|
+
cloned_executor.set_execution_mode(mode)
|
|
42
|
+
|
|
43
|
+
start = time.perf_counter()
|
|
44
|
+
if mode == "async":
|
|
45
|
+
await cloned_executor.run_async(task_list)
|
|
46
|
+
else:
|
|
47
|
+
cloned_executor.run(task_list)
|
|
48
|
+
use_time.append([time.perf_counter() - start])
|
|
49
|
+
|
|
50
|
+
use_time_table: str = format_table(use_time, execution_modes, ["Time"])
|
|
51
|
+
print(f"Use time:\n{use_time_table}\n")
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
"use_time": use_time,
|
|
55
|
+
"execution_modes": execution_modes,
|
|
56
|
+
"table": use_time_table,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
async def benchmark_graph(
|
|
61
|
+
sync_graph: TaskGraph,
|
|
62
|
+
async_graph: TaskGraph,
|
|
63
|
+
init_tasks_dict: Mapping[str, Iterable[Any]],
|
|
64
|
+
graph_modes: list[str] | None = None,
|
|
65
|
+
execution_modes: list[str] | None = None,
|
|
66
|
+
) -> dict[str, Any]:
|
|
67
|
+
"""
|
|
68
|
+
对任务图进行基准测试,覆盖 ``graph_mode × execution_mode`` 的全部组合。
|
|
69
|
+
|
|
70
|
+
- ``sync_graph`` 用于 ``execution_mode in {"serial", "thread"}`` 的单元格;
|
|
71
|
+
- ``async_graph`` 用于 ``execution_mode == "async"`` 的单元格;
|
|
72
|
+
- ``graph_mode`` 决定当前单元格使用 ``run()`` 还是 ``run_async()`` 启动。
|
|
73
|
+
|
|
74
|
+
:param sync_graph: 同步任务图模板(用于 serial/thread execution_mode)
|
|
75
|
+
:param async_graph: 异步任务图模板(用于 async execution_mode)
|
|
76
|
+
:param init_tasks_dict: 初始任务字典,键为任务标签,值为任务列表
|
|
77
|
+
:param graph_modes: 要测试的图执行模式列表,默认包括 "serial", "thread", "async"
|
|
78
|
+
:param execution_modes: 执行模式列表,默认 ["serial", "thread", "async"]
|
|
79
|
+
:return: 包含测试结果的字典
|
|
80
|
+
"""
|
|
81
|
+
graph_modes = graph_modes or ["serial", "thread", "async"]
|
|
82
|
+
execution_modes = execution_modes or ["serial", "thread", "async"]
|
|
83
|
+
|
|
84
|
+
base_tasks: dict[str, list[Any]] = {
|
|
85
|
+
stage_name: list(tasks) for stage_name, tasks in init_tasks_dict.items()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
test_table_list: list[list[float]] = []
|
|
89
|
+
|
|
90
|
+
for graph_mode in graph_modes:
|
|
91
|
+
time_list: list[float] = []
|
|
92
|
+
|
|
93
|
+
for execution_mode in execution_modes:
|
|
94
|
+
cloned_graph = (
|
|
95
|
+
clone_graph(async_graph)
|
|
96
|
+
if execution_mode == "async"
|
|
97
|
+
else clone_graph(sync_graph)
|
|
98
|
+
)
|
|
99
|
+
cloned_graph.set_graph_mode(graph_mode)
|
|
100
|
+
cloned_graph.set_stage_execution_mode(execution_mode)
|
|
101
|
+
|
|
102
|
+
run_tasks: dict[str, Iterable[Any]] = {
|
|
103
|
+
stage_name: list(tasks) for stage_name, tasks in base_tasks.items()
|
|
104
|
+
}
|
|
105
|
+
start_time = time.perf_counter()
|
|
106
|
+
if graph_mode == "async":
|
|
107
|
+
await cloned_graph.run_async(run_tasks)
|
|
108
|
+
else:
|
|
109
|
+
if execution_mode == "async":
|
|
110
|
+
await asyncio.to_thread(cloned_graph.run, run_tasks)
|
|
111
|
+
else:
|
|
112
|
+
cloned_graph.run(run_tasks)
|
|
113
|
+
time_list.append(time.perf_counter() - start_time)
|
|
114
|
+
|
|
115
|
+
test_table_list.append(time_list)
|
|
116
|
+
|
|
117
|
+
time_table: str = format_table(
|
|
118
|
+
test_table_list,
|
|
119
|
+
graph_modes,
|
|
120
|
+
execution_modes,
|
|
121
|
+
"graph/execution",
|
|
122
|
+
)
|
|
123
|
+
print(f"Time table:\n{time_table}")
|
|
124
|
+
return {
|
|
125
|
+
"use_time": test_table_list,
|
|
126
|
+
"table": time_table,
|
|
127
|
+
"graph_modes": graph_modes,
|
|
128
|
+
"execution_modes": execution_modes,
|
|
129
|
+
}
|
|
@@ -31,7 +31,6 @@ def _get_clone_init_kwargs[T, R](
|
|
|
31
31
|
"max_retries": executor.max_retries,
|
|
32
32
|
"max_info": executor.max_info,
|
|
33
33
|
"enable_duplicate_check": executor.enable_duplicate_check,
|
|
34
|
-
"persist_result": executor.persist_result,
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
|
|
@@ -59,7 +58,6 @@ def clone_stage[T, R](
|
|
|
59
58
|
:return: 克隆节点
|
|
60
59
|
"""
|
|
61
60
|
kwargs: dict[str, Any] = _get_clone_init_kwargs(stage)
|
|
62
|
-
kwargs["stage_mode"] = stage.get_stage_mode()
|
|
63
61
|
|
|
64
62
|
stage_cls = type(stage)
|
|
65
63
|
init_params = set(inspect.signature(stage_cls.__init__).parameters.keys()) - {
|
|
@@ -106,10 +104,12 @@ def clone_graph(graph: TaskGraph) -> TaskGraph:
|
|
|
106
104
|
:param graph: 要克隆的任务图
|
|
107
105
|
:return: 克隆任务图
|
|
108
106
|
"""
|
|
109
|
-
#
|
|
107
|
+
# 通过广度优先遍历收集所有节点(沿用任务图有序图的出边顺序)
|
|
110
108
|
visited: set[str] = set()
|
|
111
109
|
ordered_stages: list[AnyTaskStage] = []
|
|
112
|
-
queue: deque[AnyTaskStage] = deque(
|
|
110
|
+
queue: deque[AnyTaskStage] = deque(
|
|
111
|
+
graph.stage_dict[source_name] for source_name in graph.get_source_names()
|
|
112
|
+
)
|
|
113
113
|
while queue:
|
|
114
114
|
stage: AnyTaskStage = queue.popleft()
|
|
115
115
|
stage_name: str = stage.get_name()
|
|
@@ -117,7 +117,7 @@ def clone_graph(graph: TaskGraph) -> TaskGraph:
|
|
|
117
117
|
continue
|
|
118
118
|
visited.add(stage_name)
|
|
119
119
|
ordered_stages.append(stage)
|
|
120
|
-
for next_stage_name in graph.out_edges.get(stage_name, []):
|
|
120
|
+
for next_stage_name in graph.order_graph.out_edges.get(stage_name, []):
|
|
121
121
|
next_stage: AnyTaskStage = graph.stage_dict[next_stage_name]
|
|
122
122
|
queue.append(next_stage)
|
|
123
123
|
|
|
@@ -129,14 +129,11 @@ def clone_graph(graph: TaskGraph) -> TaskGraph:
|
|
|
129
129
|
# 构建新的任务图
|
|
130
130
|
all_cloned_stages: list[AnyTaskStage] = list(name_map.values())
|
|
131
131
|
|
|
132
|
-
cloned_graph: TaskGraph = TaskGraph(
|
|
133
|
-
name=graph.name,
|
|
134
|
-
schedule_mode=graph.schedule_mode,
|
|
135
|
-
)
|
|
132
|
+
cloned_graph: TaskGraph = TaskGraph(name=graph.name, graph_mode=graph.graph_mode)
|
|
136
133
|
cloned_graph.set_stages(all_cloned_stages)
|
|
137
134
|
|
|
138
135
|
# 重建连接
|
|
139
|
-
for from_name, to_names in graph.out_edges.items():
|
|
136
|
+
for from_name, to_names in graph.order_graph.out_edges.items():
|
|
140
137
|
if not to_names:
|
|
141
138
|
continue
|
|
142
139
|
cloned_from: AnyTaskStage = name_map[from_name]
|