Tworzenie zależności zadań w celu uruchamiania zadań, które zależą od innych zadań

W przypadku zależności zadań usługi Batch można tworzyć zadania zaplanowane do wykonania w węzłach obliczeniowych po zakończeniu co najmniej jednego zadania nadrzędnego. Można na przykład utworzyć zadanie, które renderuje każdą ramkę filmu 3D z oddzielnymi zadaniami równoległymi. Zadanie końcowe scala renderowane ramki do kompletnego filmu dopiero po pomyślnym renderowaniu wszystkich ramek. Innymi słowy, końcowe zadanie jest zależne od poprzednich zadań nadrzędnych.

Niektóre scenariusze, w których przydatne są zależności zadań:

  • Obciążenia w stylu MapReduce w chmurze.
  • Zadania, których zadania przetwarzania danych można wyrazić jako skierowany graf acykliczny (DAG).
  • Procesy przed renderowaniem i po renderowaniu, w których każde zadanie musi zostać ukończone przed rozpoczęciem następnego zadania.
  • Każde inne zadanie, w którym podrzędne zadania zależą od danych wyjściowych podrzędnych podrzędnych zadań podrzędnych.

Domyślnie zadania zależne są zaplanowane do wykonania dopiero po pomyślnym zakończeniu zadania nadrzędnego. Opcjonalnie można określić akcję zależności , aby zastąpić domyślne zachowanie i uruchomić zadanie zależne, nawet jeśli zadanie nadrzędne zakończy się niepowodzeniem.

W tym artykule omówiono sposób konfigurowania zależności zadań przy użyciu biblioteki .NET usługi Batch . Najpierw pokazano, jak włączyć zależność zadania od zadań, a następnie pokazać, jak skonfigurować zadanie z zależnościami. Opisujemy również sposób określania akcji zależności do uruchamiania zadań zależnych, jeśli element nadrzędny zakończy się niepowodzeniem. Na koniec omówimy scenariusze zależności obsługiwane przez usługę Batch.

Włączanie zależności zadań

Aby używać zależności zadań w aplikacji usługi Batch, należy najpierw skonfigurować zadanie do korzystania z zależności zadań. Na platformie .NET usługi Batch włącz ją w ramach zadania CloudJob , ustawiając właściwość UsesTaskDependencies na true:

CloudJob unboundJob = batchClient.JobOperations.CreateJob( "job001",
    new PoolInformation { PoolId = "pool001" });

// IMPORTANT: This is REQUIRED for using task dependencies.
unboundJob.UsesTaskDependencies = true;

W poprzednim fragmencie kodu "batchClient" jest wystąpieniem klasy BatchClient .

Tworzenie zadań zależnych

Aby utworzyć zadanie zależne od ukończenia co najmniej jednego zadania nadrzędnego, można określić, że zadanie "zależy od" innych zadań. Na platformie .NET usługi Batch skonfiguruj właściwość CloudTask.DependsOn z wystąpieniem klasy TaskDependencies :

// Task 'Flowers' depends on completion of both 'Rain' and 'Sun'
// before it is run.
new CloudTask("Flowers", "cmd.exe /c echo Flowers")
{
    DependsOn = TaskDependencies.OnIds("Rain", "Sun")
},

Ten fragment kodu tworzy zależne zadanie o identyfikatorze zadania "Kwiaty". Zadanie "Kwiaty" zależy od zadań "Deszcz" i "Słońce". Zadanie "Kwiaty" zostanie zaplanowane do uruchomienia w węźle obliczeniowym dopiero po pomyślnym ukończeniu zadań "Deszcz" i "Sun".

Uwaga

Domyślnie zadanie jest uznawane za ukończone pomyślnie, gdy znajduje się w stanie ukończonym, a jego kod zakończenia to 0. Na platformie .NET usługi Batch oznacza to, że wartość właściwości CloudTask.State to Completed , a wartość właściwości TaskExecutionInformation.ExitCode w usłudze CloudTask to 0. Aby dowiedzieć się, jak to zmienić, zobacz sekcję Akcje zależności .

Scenariusze zależności

Istnieją trzy podstawowe scenariusze zależności zadań, których można użyć w Azure Batch: zależność jeden do jednego, jeden do wielu i zakres identyfikatorów zadań. Te trzy scenariusze można połączyć, aby zapewnić czwarty scenariusz: wiele do wielu.

Scenariusz Przykład Ilustracji
Jeden do jednego taskB zależy od zadaniaA taskB

nie będzie zaplanowane do wykonania, dopóki zadanieA nie zakończy się pomyślnie

Diagram przedstawiający scenariusz zależności zadania jeden do jednego.
Jeden do wielu taskC zależy zarówno od zadaniaA, jak i taskBtaskC nie będzie zaplanowane do wykonania, dopóki zadanieA i zadanieB

nie zostaną ukończone pomyślnie

Diagram przedstawiający scenariusz zależności zadania jeden do wielu.
Zakres identyfikatorów zadań taskD zależy od zakresu zadań

podrzędnychD nie zostaną zaplanowane do wykonania, dopóki zadania z identyfikatorami od 1 do 10 zostały ukończone pomyślnie

Diagram przedstawiający scenariusz zależności zakresu zadań zakresu zadań.

Porada

Można tworzyć relacje wiele-do-wielu , takie jak zadania C, D, E i F, które zależą od zadań A i B. Jest to przydatne, na przykład w scenariuszach równoległego przetwarzania wstępnego, w których podrzędne zadania zależą od danych wyjściowych wielu nadrzędnych zadań.

W przykładach w tej sekcji zależne zadanie jest uruchamiane tylko po pomyślnym zakończeniu zadań nadrzędnych. To zachowanie jest domyślnym zachowaniem zadania zależnego. Zadanie zależne można uruchomić po niepomyślnym zadaniu nadrzędnym, określając akcję zależności , aby zastąpić domyślne zachowanie.

Jeden do jednego

W relacji jeden do jednego zadanie zależy od pomyślnego ukończenia jednego zadania nadrzędnego. Aby utworzyć zależność, podaj pojedynczy identyfikator zadania do metody statycznej TaskDependencies.OnId podczas wypełniania właściwości CloudTask.DependsOn .

// Task 'taskA' doesn't depend on any other tasks
new CloudTask("taskA", "cmd.exe /c echo taskA"),

// Task 'taskB' depends on completion of task 'taskA'
new CloudTask("taskB", "cmd.exe /c echo taskB")
{
    DependsOn = TaskDependencies.OnId("taskA")
},

Jeden do wielu

W relacji jeden do wielu zadanie zależy od ukończenia wielu zadań nadrzędnych. Aby utworzyć zależność, podaj kolekcję określonych identyfikatorów zadań do metody statycznej TaskDependencies.OnIds podczas wypełniania właściwości CloudTask.DependsOn .

// 'Rain' and 'Sun' don't depend on any other tasks
new CloudTask("Rain", "cmd.exe /c echo Rain"),
new CloudTask("Sun", "cmd.exe /c echo Sun"),

// Task 'Flowers' depends on completion of both 'Rain' and 'Sun'
// before it is run.
new CloudTask("Flowers", "cmd.exe /c echo Flowers")
{
    DependsOn = TaskDependencies.OnIds("Rain", "Sun")
},

Ważne

Tworzenie zadania zależnego zakończy się niepowodzeniem, jeśli łączna długość identyfikatorów zadań nadrzędnych jest większa niż 64000 znaków. Aby określić dużą liczbę zadań nadrzędnych, rozważ użycie zakresu identyfikatorów zadań.

Zakres identyfikatorów zadań

W zależności od zakresu zadań nadrzędnych zadanie zależy od ukończenia zadań, których identyfikatory znajdują się w określonym zakresie.

Aby utworzyć zależność, podaj pierwsze i ostatnie identyfikatory zadań w zakresie do metody statycznej TaskDependencies.OnIdRange podczas wypełniania właściwości CloudTask.DependsOn .

Ważne

W przypadku używania zakresów identyfikatorów zadań dla zależności tylko zadania z identyfikatorami reprezentującymi wartości całkowite zostaną wybrane przez zakres. Na przykład zakres 1..10 wybierze zadania 3 i 7, ale nie 5flamingoes.

Zera wiodące nie są istotne podczas oceniania zależności zakresu, więc zadania z identyfikatorami ciągów 404004 i będą znajdować się w zakresie, ponieważ wszystkie będą traktowane jako zadanie 4, pierwszy do ukończenia spełni zależność.

Aby zadanie zależne było uruchamiane, każde zadanie w zakresie musi spełniać zależność, kończąc pomyślnie lub kończąc z niepowodzeniem mapowanym na akcję zależności ustawioną na Wartość Spełnij.

// Tasks 1, 2, and 3 don't depend on any other tasks. Because
// we will be using them for a task range dependency, we must
// specify string representations of integers as their ids.
new CloudTask("1", "cmd.exe /c echo 1"),
new CloudTask("2", "cmd.exe /c echo 2"),
new CloudTask("3", "cmd.exe /c echo 3"),

// Task 4 depends on a range of tasks, 1 through 3
new CloudTask("4", "cmd.exe /c echo 4")
{
    // To use a range of tasks, their ids must be integer values.
    // Note that we pass integers as parameters to TaskIdRange,
    // but their ids (above) are string representations of the ids.
    DependsOn = TaskDependencies.OnIdRange(1, 3)
},

Akcje zależności

Domyślnie zależne zadanie lub zestaw zadań jest uruchamiany tylko po pomyślnym zakończeniu zadania nadrzędnego. W niektórych scenariuszach możesz chcieć uruchamiać zadania zależne nawet wtedy, gdy zadanie nadrzędne zakończy się niepowodzeniem. Domyślne zachowanie można zastąpić, określając akcję zależności , która wskazuje, czy zależne zadanie kwalifikuje się do uruchomienia.

Załóżmy na przykład, że zależne zadanie oczekuje na dane od ukończenia zadania nadrzędnego. Jeśli zadanie nadrzędne zakończy się niepowodzeniem, zależne zadanie może nadal być w stanie uruchomić przy użyciu starszych danych. W takim przypadku akcja zależności może określić, że zależne zadanie kwalifikuje się do uruchomienia pomimo niepowodzenia zadania nadrzędnego.

Akcja zależności jest oparta na warunku zakończenia zadania nadrzędnego. Możesz określić akcję zależności dla dowolnego z następujących warunków zakończenia:

  • Gdy wystąpi błąd przetwarzania wstępnego.
  • Po wystąpieniu błędu przekazywania pliku. Jeśli zadanie kończy działanie z kodem zakończenia określonym za pośrednictwem exitCodes lub exitCodeRanges, a następnie napotka błąd przekazywania pliku, akcja określona przez kod zakończenia ma pierwszeństwo.
  • Po zakończeniu zadania z kodem zakończenia zdefiniowanym przez właściwość ExitCodes .
  • Gdy zadanie kończy działanie z kodem zakończenia, który mieści się w zakresie określonym przez właściwość ExitCodeRanges .
  • Domyślny przypadek, jeśli zadanie kończy działanie z kodem zakończenia niezdefiniowany przez exitCodes lub ExitCodeRanges, lub jeśli zadanie kończy działanie z błędem przetwarzania wstępnego i właściwość PreProcessingError nie jest ustawiona, lub jeśli zadanie zakończy się niepowodzeniem z błędem przekazywania pliku i właściwość FileUploadError nie jest ustawiona.

W przypadku platformy .NET te warunki są definiowane jako właściwości klasy ExitConditions .

Aby określić akcję zależności, ustaw właściwość ExitOptions.DependencyAction dla warunku zakończenia na jedną z następujących wartości:

  • Spełnianie wymagań: wskazuje, że zadania zależne kwalifikują się do uruchomienia, jeśli zadanie nadrzędne kończy działanie z określonym błędem.
  • Blokuj: wskazuje, że zadania zależne nie kwalifikują się do uruchomienia.

Ustawieniem domyślnym właściwości DependencyAction jest Spełnianie dla kodu zakończenia 0 i Blokuj dla wszystkich innych warunków zakończenia.

Poniższy fragment kodu ustawia właściwość DependencyAction dla zadania nadrzędnego. Jeśli zadanie nadrzędne kończy się z błędem przetwarzania wstępnego lub z określonymi kodami błędów, zadanie zależne zostanie zablokowane. Jeśli zadanie nadrzędne kończy działanie z innym błędem innym niż zero, zależne zadanie kwalifikuje się do uruchomienia.

// Task A is the parent task.
new CloudTask("A", "cmd.exe /c echo A")
{
    // Specify exit conditions for task A and their dependency actions.
    ExitConditions = new ExitConditions
    {
        // If task A exits with a pre-processing error, block any downstream tasks (in this example, task B).
        PreProcessingError = new ExitOptions
        {
            DependencyAction = DependencyAction.Block
        },
        // If task A exits with the specified error codes, block any downstream tasks (in this example, task B).
        ExitCodes = new List<ExitCodeMapping>
        {
            new ExitCodeMapping(10, new ExitOptions() { DependencyAction = DependencyAction.Block }),
            new ExitCodeMapping(20, new ExitOptions() { DependencyAction = DependencyAction.Block })
        },
        // If task A succeeds or fails with any other error, any downstream tasks become eligible to run 
        // (in this example, task B).
        Default = new ExitOptions
        {
            DependencyAction = DependencyAction.Satisfy
        }
    }
},
// Task B depends on task A. Whether it becomes eligible to run depends on how task A exits.
new CloudTask("B", "cmd.exe /c echo B")
{
    DependsOn = TaskDependencies.OnId("A")
},

Przykład kodu

Przykładowy projekt TaskDependencies w usłudze GitHub przedstawia:

  • Jak włączyć zależność zadania od zadania.
  • Jak tworzyć zadania zależne od innych zadań.
  • Jak wykonywać te zadania w puli węzłów obliczeniowych.

Następne kroki