5 votes

Manière correcte d'annuler le bloc de flux de données TPL

J'utilise TPL blocs pour effectuer une opération qui peut être annulée par l'utilisateur : J'ai trouvé deux options, dans la première j'annule tout le bloc mais n'annule pas l'opération à l'intérieur du bloc, comme ceci :

_downloadCts = new CancellationTokenSource();

var processBlockV1 = new TransformBlock<int, List<int>>(construct =>
{
    List<int> properties = GetPropertiesMethod(construct );
    var entities = properties
        .AsParallel()
        .Select(DoSometheningWithData)
        .ToList();
    return entities;
}, new ExecutionDataflowBlockOptions() { CancellationToken = _downloadCts.Token });

et la seconde j'annule l'opération interne, mais pas le bloc lui-même :

var processBlockV2 = new TransformBlock<int, List<int>>(construct =>
{
    List<int> properties = GetPropertiesMethod(construct);
    var entities = properties
        .AsParallel().WithCancellation(_downloadCts.Token)
        .Select(DoSometheningWithData)
        .ToList();
    return entities;
});

Si j'ai bien compris, la première option annule tout le bloc, ce qui entraîne l'arrêt de tout le pipeline. Ma question est de savoir si cela annulera également l'opération interne et disposera de toutes les ressources s'il y en a (StreamReaders ouverts, etc.) ou s'il vaut mieux choisir la deuxième option car je pourrai alors m'assurer moi-même que tout est annulé et nettoyé, puis je pourrai utiliser des moyens (programmation ferroviaire) pour faire remonter les données. OperationCanceledException dans le tuyau et m'en occuper où je veux ?

3voto

Theodor Zoulias Points 1088

Ces deux options ne sont pas équivalentes.

  1. La première option ( CancellationToken = _downloadCts.Token ) rendra le processBlockV1 pour rejeter tous les messages qui se trouvent actuellement dans sa mémoire tampon (son bloc InputCount la propriété deviendra 0 ), et cesser d'accepter de nouveaux messages (en invoquant ses Post retournera invariablement false ). Le traitement des messages en cours ne s'arrêtera pas pour autant. Ceux-ci seront traités entièrement, mais ne seront pas propagés à d'autres blocs liés. Après le traitement de ces messages, le bloc se terminera dans un état annulé (sa fonction Completion.Status la propriété deviendra Canceled ).

  2. La deuxième option (annulation des opérations intérieures) n'aura aucun effet sur le bloc dans son ensemble. Les blocs Dataflow tolèrent toute OperationCanceledException jetés de leur fonction de traitement, et ignorent simplement l'élément défectueux pour passer à l'élément suivant. Ainsi, après l'annulation du jeton, tous les messages postés seront toujours traités, et le bloc continuera à en accepter d'autres. Il ne propagera rien aux blocs qui lui sont liés, car tous les éléments lanceront le jeton OperationCanceledException et être ignorés. Dans l'exemple spécifique, le GetPropertiesMethod sera invoquée pour toutes les construct et imposera donc un retard à l'achèvement du bloc. L'état final du bloc sera RanToCompletion .

Il est important de savoir que les blocs Dataflow prennent au sérieux le concept de Completion . Ils attendront que tout ce qu'ils savent s'arrête de fonctionner avant de signaler leur achèvement. Si vous voulez qu'ils se terminent prématurément et laissent derrière eux des tâches encore en cours d'exécution, vous devrez recourir à des astuces comme les suivantes envelopper vos tâches avec des enveloppes annulables .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X