Condividi tramite


Creare relazioni tra attività per eseguire attività che dipendono da altre attività

Tramite le dipendenze delle attività di Batch si creano attività di cui pianificare l'esecuzione nei nodi di calcolo dopo il completamento di una o più attività padre. Ad esempio, è possibile creare un processo che esegue il rendering di ogni fotogramma di un film 3D con le attività parallele separate. L'attività finale unisce i fotogrammi sottoposti a rendering in un filmato completo solo dopo che è stato eseguito il rendering di tutti i fotogrammi. In altre parole, l'attività finale dipende dalle attività padre precedenti.

Ecco alcuni degli scenari in cui le dipendenze delle attività sono utili:

  • Carichi di lavoro di tipo MapReduce nel cloud.
  • Processi le cui attività di elaborazione dati può essere espressa come grafo aciclico diretto (DAG).
  • Processi di pre-rendering e post-rendering, in cui ogni attività deve essere completata prima di poter avviare quella successiva.
  • Qualsiasi altro processo in cui le attività downstream dipendono l'output delle attività upstream.

Per impostazione predefinita, l'esecuzione delle attività dipendenti è pianificata solo dopo il corretto completamento dell'attività padre. Facoltativamente, è possibile specificare un'azione di dipendenza per eseguire l'override del comportamento predefinito ed eseguire l'attività dipendente anche se l'attività padre ha esito negativo.

Questo articolo illustra la configurazione di relazioni tra attività tramite la libreria Batch .NET. Viene illustrato prima come abilitare le dipendenze tra attività nei processi, quindi viene spiegato come configurare un'attività con dipendenze. Viene inoltre descritto come specificare un'azione di dipendenza per l'esecuzione di attività dipendenti se l'attività padre non riesce. Vengono infine illustrati gli scenari delle relazione supportate da Batch.

Abilitare le relazioni tra attività

Per usare le dipendenze delle attività nell'applicazione Batch, è innanzitutto necessario configurare il processo per l'uso delle dipendenze. In Batch .NET abilitare la funzionalità in CloudJob impostando la rispettiva proprietà UsesTaskDependencies su true:

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

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

Nel frammento di codice precedente "batchClient" è un'istanza della classe BatchClient.

Creare attività dipendenti

Per creare un'attività che dipende dal completamento di una o più attività padre, è possibile specificare che l'attività "dipende" dalle altre attività. In Batch .NET configurare la proprietà CloudTask.DependsOn con un'istanza della classe 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")
},

Questo frammento di codice crea un'attività dipendente con ID attività "Flowers". L'attività "Flowers" dipende dalle attività "Rain" e "Sun". L'esecuzione dell'attività "Flowers" in un nodo di calcolo verrà pianificata solo dopo il corretto completamento delle attività "Rain" e "Sun".

Nota

Per impostazione predefinita, un'attività viene considerata correttamente completata quando l'attività è in stato completato e il codice di uscita è 0. In Batch .NET ciò corrisponde a un valore della proprietà CloudTask.State pari a Completed e il valore della proprietà TaskExecutionInformation.ExitCode è 0. Per informazioni su come modificare questa impostazione, vedere la sezione Azioni di dipendenza.

scenari delle relazione

In Azure Batch è possibile usare tre scenari di relazioni tra attività di base, ovvero uno-a-uno, uno-a-molti e la relazione tra intervalli di ID. Questi tre scenari possono essere combinati per fornire un quarto scenario: molti-a-molti.

Scenario Esempio Illustrazione
Uno-a-uno taskB dipende da taskA

taskB non verrà pianificato per l'esecuzione fino al completamento corretto di taskA

Diagramma che mostra lo scenario di dipendenza dell'attività uno-a-uno.
Uno-a-molti taskC dipende da taskA e taskB

taskC non verrà pianificato per l'esecuzione fino al completamento corretto di taskA e taskB

Diagramma che mostra lo scenario di dipendenza delle attività uno-a-molti.
Intervallo di ID attività taskD dipende da un intervallo di attività

taskD non verrà pianificato per l'esecuzione fino a quando le attività con ID da 1 a 10 non saranno state completate correttamente

Diagramma che mostra lo scenario di dipendenza dell'attività intervallo ID attività.

Suggerimento

È possibile creare relazioni molti-a-molti, ad esempio relazioni in cui le attività C, D, E e F dipendono dalle attività A e B. Questo tipo di relazione risulta utile, ad esempio, negli scenari di pre-elaborazione parallelizzata, in cui le attività downstream dipendono dall'output di più attività upstream.

Negli esempi di questa sezione un'attività dipendente viene eseguita solo dopo che le attività padre vengono completate correttamente. Questo comportamento è quello predefinito per un'attività dipendente. È possibile eseguire un'attività dipendente dopo che un'attività padre non riesce specificando un'azione di dipendenza per sostituire il comportamento predefinito.

Uno-a-uno

In una relazione uno-a-uno un'attività dipende dal corretto completamento di una sola attività padre. Per creare la dipendenza, specificare un solo ID attività nel metodo statico TaskDependencies.OnId quando si popola la proprietà DependsOn di CloudTask.

// 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")
},

Uno-a-molti

In una relazione uno-a-molti un'attività dipende dal completamento di più attività padre. Per creare la dipendenza, specificare una raccolta di ID attività specifiche nel metodo statico TaskDependencies.OnId quando si popola la proprietà DependsOn di CloudTask.

// '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")
},

Importante

La creazione dell'attività dipendente avrà esito negativo se la lunghezza combinata degli ID attività padre è maggiore di 64000 caratteri. Per specificare un numero elevato di attività padre, è consigliabile usare invece un intervallo di ID attività.

Intervallo di ID attività

In una dipendenza da un intervallo di attività padre un'attività dipende dal completamento delle attività il cui ID è compreso all'interno di un intervallo specificato.

Per creare la dipendenza, specificare il primo e l'ultimo ID attività dell'intervallo nel metodo statico TaskDependencies.OnIdRange quando si popola la proprietà DependsOn di CloudTask.

Importante

Quando si usano intervalli di ID attività per le dipendenze, verranno selezionate solo le attività con ID che rappresentano valori interi. Ad esempio, l'intervallo 1..10 selezionerà le attività 3 e 7, ma non 5flamingoes.

Gli zeri iniziali non sono rilevanti per la valutazione delle dipendenze nell'intervallo, per cui le attività con gli identificatori di stringa 4, 04 e 004 saranno tutte all'interno dell'intervallo e verranno tutte considerate attività 4, in modo che la prima a essere completata soddisferà la dipendenza.

Per l'attività dipendente da eseguire, ogni attività compresa nell'intervallo deve soddisfare la dipendenza attraverso il corretto completamento o il completamento con un errore mappato a un'azione di dipendenza impostata su Satisfy.

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

Azioni di dipendenza

Per impostazione predefinita, un'attività o un set di attività dipendenti vengono eseguite solo dopo il corretto completamento di un'attività padre. In alcuni scenari potrebbe essere necessario eseguire attività dipendenti anche se l'attività padre non riesce. È possibile eseguire l'override del comportamento predefinito specificando un'azione di dipendenza che indica se un'attività dipendente è idonea per l'esecuzione.

Si supponga, ad esempio, un'attività dipendente in attesa di dati dal completamento dell'attività upstream. Se l'attività upstream non riesce, l'attività dipendente potrebbe comunque essere eseguita usando dati meno recenti. In questo caso, un'azione di dipendenza può specificare che l'attività dipendente è idonea per l'esecuzione nonostante l'errore dell'attività padre.

Un'azione di dipendenza è basata su una condizione di uscita per l'attività padre. È possibile specificare un'azione di dipendenza per una delle condizioni di uscita seguenti:

  • Quando si verifica un errore di pre-elaborazione.
  • Quando si verifica un errore di caricamento dei file. Se l'attività si chiude con un codice di uscita specificato tramite exitCodes o exitCodeRanges e quindi si verifica un errore di caricamento dei file, l'azione specificata dal codice di uscita ha la precedenza.
  • Quando l'attività termina con un codice di uscita definito dalla proprietà ExitCodes.
  • Quando l'attività termina con un codice di uscita compreso in un intervallo specificato dalla proprietà ExitCodeRanges.
  • Il caso predefinito, ovvero se l'attività si chiude con un codice di uscita non definito da ExitCodes o ExitCodeRanges oppure se l'attività si chiude con un errore di pre-elaborazione e la proprietà PreProcessingError non è stata configurata o se l'attività ha esito negativo con un errore di caricamento dei file e la proprietà FileUploadError non è stata configurata.

Per .NET, queste condizioni vengono definite come proprietà della classe ExitConditions.

Per specificare un'azione di dipendenza, impostare la proprietà ExitOptions.DependencyAction per la condizione di uscita:

  • Soddisfa: indica che le attività dipendenti sono idonee per l'esecuzione se l'attività padre viene chiusa con un errore specificato.
  • Blocca: indica che le attività dipendenti non sono idonee per l'esecuzione.

L'impostazione predefinita per la proprietà DependencyAction è Satisfy per il codice di uscita 0 e Block per tutte le altre condizioni di uscita.

Il frammento di codice seguente imposta la proprietà DependencyAction per un'attività padre. Se l'attività padre termina con un errore di pre-elaborazione o con i codici di errore specificati, l'attività dipendente viene bloccata. Se l'attività padre termina con qualsiasi altro errore diverso da zero, l'attività dipendente è idonea per l'esecuzione.

// 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")
},

Esempio di codice

Il progetto di esempio TaskDependencies in GitHub illustra:

  • Come abilitare la dipendenza delle attività in un processo.
  • Come creare attività che dipendono da altre attività.
  • Come eseguire queste attività in un pool di nodi di calcolo.

Passaggi successivi