[TPL] Erreur courante d'utilisation du CancellationToken sur un Parallel.ForEach

Cela fait déjà un certain nombre de fois que je tombe sur un code similaire à celui-ci :

private void DoJobs(IEnumerable<Object> data,CancellationToken token)
{
	// Option pour permettre l'annulation des jobs
	ParallelOptions options = new ParallelOptions {CancellationToken = token};
	Parallel.ForEach(
		data,
		options,
		DoJob);
}
 
private void DoJob(Object data)
{
	// ...
}

Si la méthode Cancel de la CancellationToken Source à l'origine du token est appelée avant le lancement de notre méthode DoJobs, il y aura une exception sur le Parallel.ForEach.

cancelexceptiontoken


Certain corrigerons le tir en remplaçant leur code par :

private void DoJobs(IEnumerable<Object> data,CancellationToken token)
{
	try
	{
		// Option pour permettre l'annulation des jobs
		ParallelOptions options = new ParallelOptions { CancellationToken = token };

		Parallel.ForEach(
			data,
			options,
			DoJob);
	}
	catch (OperationCanceledException ex)
	{
		Trace.TraceError(ex.Message);
	}
}

C'est effectivement une solution. Mais dans le cas où l'on peut savoir si une annulation est en cours avant même de lancer une autre opération, pourquoi n'utiliserions-nous pas plutôt un code tel que celui-ci?

private void DoJobs(IEnumerable<Object> data,CancellationToken token)
{
	// Annulation possible
	if (token.IsCancellationRequested) return;

	// Option pour permettre l'annulation des jobs
	ParallelOptions options = new ParallelOptions { CancellationToken = token };

	Parallel.ForEach(
		data,
		options,
		DoJob);
}

Bien entendu, les plus prudents iront peut-être vers un

private void DoJobs(IEnumerable<Object> data,CancellationToken token)
{
	// Annulation possible
	if (token.IsCancellationRequested) return;
	try
	{
		// Option pour permettre l'annulation des jobs
		ParallelOptions options = new ParallelOptions { CancellationToken = token };

		Parallel.ForEach(
			data,
			options,
			DoJob);
	}
	catch (OperationCanceledException ex)
	{
		Trace.TraceError(ex.Message);
	}
}

Et vous, comment préférez-vous, jouer vous avec les CancellationToken et leurs sources?

PS : j’ai voulu présenter ici un cas simple. Je ne passe donc pas de token à ma méthode DoJob dans cet exemple.

Jérémy Jeanson

Comments

You have to be logged in to comment this post.