Tryby wykonywania przepływu pracy

Podczas uruchamiania przepływu pracy na platformie .NET tryb wykonywania kontroluje sposób przetwarzania superkroków i sposobu dostarczania zdarzeń do odbiorcy. Klasa InProcessExecution udostępnia dwa tryby wykonywania: OffThread i Lockstep.

Przegląd

OffThread (ustawienie domyślne) Lockstep
Wykonanie superkroku Wątek działający w tle Wątek konsumenta
Dostarczanie zdarzeń Natychmiastowe, w miarę wywoływanych zdarzeń Przetworzone wsadowo po zakończeniu każdej superkroki
Wykonywanie kroków Niezależne od przetwarzania zdarzeń Wstrzymano do momentu, dopóki zdarzenia wsadowe nie zostaną przetworzone
Współbieżność W momencie, gdy uruchamiane są superkroki, użytkownik odczytuje zdarzenia. Wykonywanie naprzemienne konsumenta i nadrzędnego kroku
Najlepsze dla Przesyłanie strumieniowe w czasie rzeczywistym, scenariusze produkcyjne Testowanie, debugowanie, deterministyczne porządkowanie

OffThread

OffThread jest domyślnym trybem wykonywania. Superkroki działają w tle, a zdarzenia są strumieniowane natychmiast po ich wywołaniu za pomocą implementacji kanałowej.

// 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);

Jak to działa

  1. Zadanie w tle uruchamia superkroki w sposób ciągły, gdy komunikaty oczekują.
  2. Ponieważ funkcje wykonawcze dają dane wyjściowe lub zdarzenia, wynikowe WorkflowEvent obiekty są zapisywane w niezwiązanym Channel<WorkflowEvent>obiekcie .
  3. Odbiorca odczytuje zdarzenia z kanału za pośrednictwem WatchStreamAsync, odbierając je w czasie rzeczywistym, gdy są produkowane.
  4. Gdy wszystkie superkroki są ukończone i nie pozostają żadne wiadomości, działanie zostaje zakończone ze statusem Idle lub PendingRequests.

Ponieważ pętla superkrok i odbiorca są uruchamiane współbieżnie, zdarzenia pojawiają się natychmiast, kiedy są wywoływane — nie ma opóźnienia buforowania. Dzięki temu funkcja OffThread jest idealna w scenariuszach przesyłania strumieniowego, w których dostarczanie zdarzeń o małych opóźnieniach ma znaczenie, takie jak wyświetlanie aktualizacji tokenu po tokenie w interfejsie użytkownika.

Współbieżne uruchomienia

Funkcja OffThread obsługuje również wariant współbieżny, który pozwala wielu przebiegom równocześnie dzielić to samo wystąpienie przepływu pracy.

await using StreamingRun run = await InProcessExecution.Concurrent.RunStreamingAsync(workflow, input);

Ważna

Współbieżne wykonywanie wymaga zadeklarowania crossRunShareable wszystkich funkcji wykonawczych w przepływie pracy (w konstruktorze) lub podania ich jako metod fabrycznych.

Lockstep

W trybie Lockstep superkroki są uruchamiane w wątku konsumenta, a nie jako zadanie w tle. Zdarzenia są gromadzone podczas każdego superkroka i emitowane jako pakiet po zakończeniu superkroka.

await using StreamingRun run = await InProcessExecution.Lockstep.RunStreamingAsync(workflow, input);

Jak to działa

  1. Użytkownik wywołuje WatchStreamAsync metodę, która napędza pętlę wykonawczą.
  2. Superkrok działa do ukończenia, a zdarzenia są gromadzone w kolejce.
  3. Po zakończeniu superkroku wszystkie zdarzenia umieszczone w kolejce zostaną zwrócone użytkownikowi.
  4. Następny superstep rozpoczyna się dopiero po otrzymaniu przez konsumenta wszystkich eventów z poprzedniego.

Ten zmienny wzorzec oznacza, że użytkownik i aparat przepływu pracy nigdy nie działają jednocześnie. Dostarczanie zdarzeń jest deterministyczne — wszystkie zdarzenia z superkroku mają gwarancję nadejścia przed jakimikolwiek zdarzeniami z następnego superkroku.

Kiedy należy używać funkcji Lockstep

Funkcja Lockstep jest przydatna, gdy:

  • Testowanie — określanie kolejności zdarzeń sprawia, że asercji są proste.
  • Debugowanie — debugowanie krokowe jest łatwiejsze, gdy wykonywanie odbywa się na wątku użytkownika.
  • Przetwarzanie uporządkowane — scenariusze, w których należy w pełni przetworzyć zdarzenia jednego superkroku przed rozpoczęciem następnego superkroku.

Wybieranie trybu wykonywania

W przypadku większości scenariuszy produkcyjnych zalecany jest domyślny tryb OffThread . Zapewnia ona najlepszą szybkość reakcji i umożliwia przepływowi pracy kontynuowanie przetwarzania podczas obsługi zdarzeń przez użytkownika.

Użyj funkcji Lockstep , gdy zachowanie deterministyczne jest ważniejsze niż wydajność, na przykład w testach jednostkowych lub sesjach debugowania.

// 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);

Wykonywanie bez przesyłania strumieniowego

Oba tryby wykonywania obsługują bezstrumieniowe wykonywanie za pośrednictwem RunAsync. W trybie bez przesyłania strumieniowego przepływ pracy jest wykonywany do zakończenia i zbiera wszystkie zdarzenia do Run obiektu, a nie przesyła ich przyrostowo:

Run run = await InProcessExecution.RunAsync(workflow, input);

// Access all emitted events
foreach (WorkflowEvent evt in run.OutgoingEvents)
{
    // Process events
}

Ponieważ wykonywanie bez użycia przesyłania strumieniowego zbiera wszystkie zdarzenia po zakończeniu, korzyści dostarczania zdarzeń w czasie rzeczywistym przez OffThread nie mają zastosowania. Podstawową różnicą między trybami w scenariuszach bez przesyłania strumieniowego jest wątkowość: Funkcja OffThread uruchamia superkroki w wątku w tle, zwalniając wątek wywołujący podczas oczekiwania na ukończenie, podczas gdy funkcja Lockstep uruchamia superkroki w wątku wywołującego, blokując go do momentu zakończenia przepływu pracy.

Wykonywanie bez przesyłania strumieniowego używa domyślnego trybu OffThread. Aby użyć funkcji Lockstep w wykonaniu niestrumieniowym:

Run run = await InProcessExecution.Lockstep.RunAsync(workflow, input);

Następne kroki

Tryby wykonywania nie mają zastosowania do przepływów pracy języka Python. Przepływy pracy języka Python używają pojedynczego modelu wykonywania, który obsługuje przetwarzanie nadrzędne i dostarczanie zdarzeń za pośrednictwem generatora asynchronicznego. Ten model jest podobny do trybu Lockstep platformy .NET — kroki nie są wykonywane, chyba że konsument aktywnie pobiera zdarzenia z generatora.

Aby uzyskać informacje na temat uruchamiania przepływów pracy języka Python, zobacz Workflow Builder & Execution (Konstruktor przepływu pracy i wykonywanie).

Podczas uruchamiania przepływu pracy w języku Go środowisko wykonywania kontroluje sposób przetwarzania superkroków i sposobu dostarczania zdarzeń do odbiorcy. Pakiet workflow/inproc uwidacznia trzy środowiska: Default/OffThread, Lockstepi .Concurrent

Przegląd

OffThread / Default Lockstep Współbieżny
Wykonanie superkroku Goroutine w tle Sterowany przez konsumenta zdarzeń Goroutine działająca w tle
Dostarczanie zdarzeń Natychmiastowe, w miarę wywoływanych zdarzeń Przetwarzane wsadowo podczas odczytu strumienia Natychmiastowe, w miarę wywoływanych zdarzeń
Najlepsze dla Przesyłanie strumieniowe w czasie rzeczywistym, scenariusze produkcyjne Testowanie, debugowanie, deterministyczne porządkowanie Współdzielone instancje przepływu pracy z powiązaniami bezpiecznymi dla współbieżności

OffThread

OffThread jest domyślnym trybem wykonywania. Są one równoważne:

stream, err := inproc.Default.RunStreaming(ctx, wf, input)
stream, err := inproc.OffThread.RunStreaming(ctx, wf, input)

Jak to działa

  1. Goroutine działająca w tle wykonuje superkroki, dopóki są oczekujące komunikaty.
  2. Ponieważ funkcje wykonawcze dają dane wyjściowe lub zdarzenia, zdarzenia przepływu pracy są zapisywane w strumieniu.
  3. Odbiorca odczytuje zdarzenia za pomocą WatchStream, odbierając je w miarę ich tworzenia.
  4. Gdy wszystkie superkroki zostaną zakończone i nie pozostaną żadne komunikaty, wykonanie kończy się ze stanem bezczynności lub oczekiwania na żądanie.

Współbieżne uruchomienia

Użyj inproc.Concurrent , gdy wszystkie powiązania funkcji wykonawczej w przepływie pracy obsługują współbieżne współdzielone wykonywanie:

stream, err := inproc.Concurrent.RunStreaming(ctx, wf, input)
if err != nil {
    return err
}
defer stream.Close(ctx)

Lockstep

W trybie lockstep wykonywanie przepływu pracy postępuje w miarę jak konsument odczytuje dane ze strumienia. Dzięki temu kolejność zdarzeń jest deterministyczna na potrzeby testów i debugowania.

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
}

Jak to działa

  1. Użytkownik wywołuje WatchStream metodę, która napędza pętlę wykonawczą.
  2. Superkrok jest wykonywany do końca, a zdarzenia są gromadzone.
  3. Zgromadzone zdarzenia są przekazywane odbiorcy.
  4. Następny superkrok rozpoczyna się dopiero po tym, jak odbiorca otrzyma zdarzenia z poprzedniego superkroku.

Kiedy należy używać funkcji Lockstep

Użyj funkcji Lockstep, gdy zachowanie deterministyczne ma większe znaczenie niż przesyłanie strumieniowe o małych opóźnieniach, takich jak testy jednostkowe, debugowanie lub scenariusze, w których chcesz w pełni przetworzyć zdarzenia jednego superkroka przed rozpoczęciem następnego kroku.

Wybieranie trybu wykonywania

W przypadku większości scenariuszy produkcyjnych użyj polecenia inproc.Default lub inproc.OffThread. Użyj inproc.Lockstep , gdy określanie kolejności zdarzeń deterministycznych jest ważniejsze niż opóźnienie przesyłania strumieniowego, na przykład w testach. Używaj inproc.Concurrent tylko wtedy, gdy każde powiązanie w przepływie pracy obsługuje współbieżne wykonywanie współdzielone.

// 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)

Wykonywanie bez przesyłania strumieniowego

Wszystkie środowiska wykonawcze obsługują również bezstrumieniowe Run, które wykonuje działanie do kolejnego zatrzymania i zapisuje wyemitowane zdarzenia w zwróconym uruchomieniu.

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)
    }
}

Następne kroki