在 .NET 中執行工作流程時, 執行模式 控制超步驟的處理方式及事件如何傳遞給消費者。 該 InProcessExecution 類別提供兩種執行模式: OffThread 與 Lockstep。
概觀
| OffThread(預設) | 步調一致 | |
|---|---|---|
| 超步驟執行 | 背景討論串 | 消費者討論串 |
| 事件傳遞 | 事件發生即時處理 | 每當一個超步驟完成後,會進行一次批次處理 |
| 步驟執行 | 獨立於事件處理 | 暫停直到批次事件被消耗 |
| 並行 | 使用者在超步驟執行期間讀取事件 | 消費者與超階執行交替 |
| 適用對象 | 即時串流與製作場景 | 測試、除錯、確定性排序 |
脫離主線程
OffThread 是 預設 的執行模式。 超步執行於背景執行緒,事件在觸發後會立即透過通道實作進行串流。
// OffThread is the default — these are equivalent:
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, input);
await using StreamingRun run = await InProcessExecution.OffThread.RunStreamingAsync(workflow, input);
運作方式
- 背景任務在訊息待處理時持續執行超步驟。
- 當執行者產生輸出或事件時,所得的
WorkflowEvent物件會寫入無界限的Channel<WorkflowEvent>中。 - 消費者透過
WatchStreamAsync從頻道讀取事件,並即時接收它們。 - 當所有超步驟完成且無訊息剩餘時,執行會以
IdleorPendingRequests狀態停止。
由於超步驟迴圈與消費者迴圈同時執行,事件一被引發便立即出現——沒有緩衝延遲。 這使得 OffThread 非常適合需要低延遲事件傳遞的串流場景,例如在使用者介面中顯示逐個標記更新。
同時運行
OffThread 也支援一種 並行 變體,允許多個執行同時共享同一工作流程實例:
await using StreamingRun run = await InProcessExecution.Concurrent.RunStreamingAsync(workflow, input);
這很重要
同時執行要求工作流程中的所有執行器都必須在建構子上宣告 crossRunShareable ,或以工廠方法形式提供。
步調一致
在 Lockstep 模式下,超步驟會執行在 消費者的執行緒 中,而非背景任務。 事件會在每個超步驟中累積,並在超步驟完成後以批次形式發出。
await using StreamingRun run = await InProcessExecution.Lockstep.RunStreamingAsync(workflow, input);
運作方式
- 消費者呼叫
WatchStreamAsync,驅動執行迴圈。 - 超級步驟執行至完成,事件會累積在佇列中。
- 超級步驟結束後,所有排隊事件都會交給消費者。
- 下一個超步驟只有在消費者收到前一步驟的所有事件後才開始。
這種交替模式意味著消費者與工作流程引擎從不會同時運作。 事件傳遞是確定性的——所有來自超步驟的事件都保證會先於下一個超步驟的任何事件抵達。
何時使用 Lockstep
Lockstep 在以下情況下非常有用:
- 測試 — 確定性事件排序使斷言變得簡單明瞭。
- 除錯 — 當執行過程停留在使用者執行緒上時,逐步除錯會更容易。
- 有序處理 ——需要在下一個超級步驟開始前,先完整處理一個超步驟的事件的情境。
選擇執行模式
大多數生產情境的建議是使用預設 OffThread 模式。 它提供最佳的響應速度,並允許工作流程在消費者處理事件時持續處理。
當確定性行為比效能更重要時,例如單元測試或除錯工作階段,請使用 Lockstep 。
// Production: OffThread (default)
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, input);
// Testing: Lockstep for deterministic behavior
await using StreamingRun run = await InProcessExecution.Lockstep.RunStreamingAsync(workflow, input);
非串流執行
兩種執行模式都支援非串流執行,這可以透過 RunAsync 來實現。 在非串流模式下,工作流程會持續執行,並將所有事件收集到物件中 Run ,而非逐步串流:
Run run = await InProcessExecution.RunAsync(workflow, input);
// Access all emitted events
foreach (WorkflowEvent evt in run.OutgoingEvents)
{
// Process events
}
由於非串流執行會在事件完成後收集所有事件,因此 OffThread 的即時事件傳遞優勢不適用。 非串流情境中模式的主要差異在於 執行緒:OffThread 會在背景執行緒執行超級步驟,釋放呼叫執行緒並等待完成;而 Lockstep 則在呼叫者執行緒上執行超級步驟,阻塞執行緒直到工作流程結束。
非串流執行則使用預設的 OffThread 模式。 在不流式執行環境下運用 Lockstep:
Run run = await InProcessExecution.Lockstep.RunAsync(workflow, input);
下一步
執行模式不適用於 Python 工作流程。 Python 工作流程使用單一執行模型,透過非同步產生器處理超步驟處理與事件傳遞。 此模型類似於 .NET Lockstep 模式——除非消費者主動從產生器拉取事件,否則步驟不會推進。
關於執行 Python 工作流程的資訊,請參見 工作流程建構器與執行。
在 Go 中執行工作流程時,執行環境控制超步驟的處理方式及事件如何傳遞給消費者。 該workflow/inproc封裝暴露三個環境:Default/OffThread、、 LockstepConcurrent和 。
概觀
| 離線討論串 / 預設 | 步調一致 | 並發 | |
|---|---|---|---|
| 超步驟執行 | 背景 goroutine | 由事件消費者驅動 | 背景 goroutine |
| 事件傳遞 | 事件發生即時處理 | 在讀取串流的同時分批處理 | 事件發生即時處理 |
| 適用對象 | 即時串流與製作場景 | 測試、除錯、確定性排序 | 具有並行安全綁定的共享工作流程實例 |
脫離主線程
OffThread 是預設的執行模式。 這兩者是等價的:
stream, err := inproc.Default.RunStreaming(ctx, wf, input)
stream, err := inproc.OffThread.RunStreaming(ctx, wf, input)
運作方式
- 背景 goroutine 會在有訊息待處理時執行超步驟。
- 當執行者產生輸出或事件時,工作流程事件會寫入串流。
- 消費者使用
WatchStream讀取事件,並在事件產生時接收它們。 - 當所有超步驟完成且無訊息時,執行會停止並顯示閒置或待處理請求狀態。
同時運行
當工作流程中所有執行者綁定都支援並行共享執行時,請使用 inproc.Concurrent :
stream, err := inproc.Concurrent.RunStreaming(ctx, wf, input)
if err != nil {
return err
}
defer stream.Close(ctx)
步調一致
在 Lockstep 模式下,工作流程的執行會隨著取用端從串流中讀取資料而推進。 這使得事件排序在測試和除錯時具有確定性。
stream, err := inproc.Lockstep.RunStreaming(ctx, wf, input)
if err != nil {
return err
}
defer stream.Close(ctx)
for evt, err := range stream.WatchStream(ctx) {
if err != nil {
return err
}
// inspect event
}
運作方式
- 消費者呼叫
WatchStream,驅動執行迴圈。 - 超級步驟會執行至完成,並累積事件。
- 累積的事件會傳回給消費者。
- 下一個超級步驟只有在消費者收到前一個超級步驟的事件後才開始。
何時使用 Lockstep
當確定性行為比低延遲串流更重要時,例如在單元測試、除錯,或是您想在下一個超級步驟開始之前,先完全處理完一個超級步驟的事件等情境中,請使用 Lockstep。
選擇執行模式
在大多數生產情境下,請使用 inproc.Default 或 inproc.OffThread。 當確定性事件排序比串流延遲更重要時,例如測試中,才會使用 inproc.Lockstep 。 只有在工作流程中每個綁定都支援並行共享執行時才使用 inproc.Concurrent 。
// Production: OffThread (default)
stream, err := inproc.Default.RunStreaming(ctx, wf, input)
if err != nil {
return err
}
defer stream.Close(ctx)
// Testing: Lockstep for deterministic behavior
testStream, err := inproc.Lockstep.RunStreaming(ctx, wf, input)
if err != nil {
return err
}
defer testStream.Close(ctx)
非串流執行
所有執行環境也支援非串流(non-stream Run),該執行會持續到下一次停止,並在回傳執行時儲存所發出的事件。
run, err := inproc.Default.Run(ctx, wf, input)
if err != nil {
return err
}
for evt := range run.NewEvents() {
if output, ok := evt.(workflow.OutputEvent); ok {
fmt.Printf("Final result: %v\n", output.Output)
}
}