35 votes

Est-il toujours mauvais d'utiliser Thread.Sleep ()?

J'ai créé une méthode d'extension pour la classe Random qui s'exécute et Action (délégué void) à des moments aléatoires:

 public static class RandomExtension
{
    private static bool _isAlive;
    private static Task _executer;

    public static void ExecuteRandomAsync(this Random random, int min, int max, int minDuration, Action action)
    {
        Task outerTask = Task.Factory.StartNew(() =>
        {
            _isAlive = true;
            _executer = Task.Factory.StartNew(() => { ExecuteRandom(min, max, action); });
            Thread.Sleep(minDuration);
            StopExecuter();
        });
    }

    private static void StopExecuter()
    {
        _isAlive = false;
        _executer.Wait();

        _executer.Dispose();
        _executer = null;
    }

    private static void ExecuteRandom(int min, int max, Action action)
    {
        Random random = new Random();

        while (_isAlive)
        {
            Thread.Sleep(random.Next(min, max));
            action();
        }
    }
}
 

Ça fonctionne bien.

Mais l'utilisation de Thread.Sleep() dans cet exemple est-elle correcte, ou ne devriez-vous généralement jamais utiliser Thread.Sleep() , quelles complications pourraient survenir? Existe-t-il des alternatives?

45voto

Patrick Hofman Points 22166

L'utilisation de Thread.Sleep mauvaise? Généralement non, si vous voulez vraiment suspendre le thread . Mais dans ce cas, vous ne voulez pas suspendre le thread , vous voulez suspendre la tâche .

Dans ce cas, vous devez donc utiliser:

 await Task.Delay(minDuration);
 

Cela ne suspendra pas l'intégralité du thread, mais uniquement la tâche unique que vous souhaitez suspendre. Toutes les autres tâches sur le même thread peuvent continuer à s'exécuter.

8voto

Yuval Itzchakov Points 13820

L'une des raisons que j'utiliserais Task.Delay sur Thread.Sleep , c'est le fait que vous pouvez passer un CancellationToken pour elle. Si l'utilisateur veut StopExecutor et l'aléatoire reçu une longue durée de durée, vous vous retrouverez bloqué pendant un long moment. D'autre part, en Task.Delay, vous pouvez annuler l'opération et il sera informé de cette annulation.

Je pense qu'il y a d'autres problèmes avec la conception que vous choisissez de faire. L' Random classe n'est pas vraiment apte à être un planificateur de tâches. Je trouve ça un peu bizarre de trouver un ExecuteRandomAsync, puisque la plupart du temps n'exécute pas un hasard, mais d'exécuter certaines arbitraire Action de toutes les X minutes.

Je voudrais au lieu de cela, aller à ce sujet d'une autre manière. Tout en gardant la plupart de l'intérieur vous avez déjà créé, mais de les mettre dans une classe différente.

public class ActionInvoker
{
    private readonly Action _actionToInvoke;

    public ActionInvoker(Action actionToInvoke)
    {
        _actionToInvoke = actionToInvoke;
        _cancellationTokenSource = new CancellationTokenSource();
    }

    private readonly CancellationTokenSource _cancellationTokenSource;
    private Task _executer;

    public void Start(int min, int max, int minDuration)
    {
        if (_executer != null)
        {
            return;
        }

        _executer = Task.Factory.StartNew(
                    async () => await ExecuteRandomAsync(min, max, _actionToInvoke),
                    _cancellationTokenSource.Token, TaskCreationOptions.LongRunning, 
                    TaskScheduler.Default)
                    .Unwrap();
    }

    private void Stop()
    {
        try
        {
            _cancellationTokenSource.Cancel();
        }
        catch (OperationCanceledException e)
        {
            // Log the cancellation.
        }
    }

    private async Task ExecuteRandomAsync(int min, int max, Action action)
    {
        Random random = new Random();

        while (!_cancellationTokenSource.IsCancellationRequested)
        {
            await Task.Delay(random.Next(min, max), _cancellationTokenSource.Token);
            action();
        }
    }
}

7voto

Mark Shevchenko Points 2566

Sleep "parle" pour le Système d'Exploitation que vous voulez suspendre le fil. Il est gourmande en ressources de fonctionnement cause de votre fil utilise de la RAM de toute façon (même si elle ne nécessite pas de temps de traitement).

Avec un pool de threads, vous pouvez utiliser les ressources du thread (f.e. RAM) pour le traitement de certaines autres petites tâches. Pour le faire, le Windows vous permet de mettre un fil à dormir dans un alertable de l'état, de sorte qu'il peut être réveillé et temporaire.

Donc, Task.Delay vous permettent de mettre des threads alertable sommeil, et, par conséquent, vous permettent d'utiliser les ressources de ces thread jusqu'alors vous n'en avez pas besoin.

4voto

insidesin Points 353

Pensez-y de cette façon.

Dormir un thread est dangereux parce que plus souvent que pas plus que l'une des tâches repose sur ce thread, pour ne pas mentionner les composants clés du programme peut le faire aussi. Ne jamais utiliser l' sleep sur les threads n'est pas appropriée, vous aurez envie de les utiliser quand ils sont bénéfiques pour votre programme.

Beaucoup de gens ont appris à ne pas dormir threads en raison du caractère imprévisible du comportement. C'est comme gérer une équipe, à la fin vous allez avoir à laisser un peu aller déjeuner et aussi longtemps que le reste de fonctionnement, tandis que ceux que vous avez choisi d'aller déjeuner sont à l'extérieur, alors vous devriez être bien et être en mesure de travailler encore.

Il suffit de ne pas envoyer les gens à déjeuner si il y a des gens dans le projet dépend de leur présence.

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