CPU amical boucle infinie
Écrire une boucle infinie est simple:
while(true){
//add whatever break condition here
}
Mais ce sera poubelle la performance du CPU. Ce thread d'exécution prendra autant que possible de la CPU de puissance.
Quel est le meilleur moyen pour diminuer l'impact sur le CPU?
L'ajout de certains Thread.Sleep(n)
devrait faire l'affaire, mais la définition d'une haute valeur de délai d'expiration pour Sleep()
méthode peut indiquer une application qui ne répond pas au système d'exploitation.
Disons que j'ai besoin pour effectuer une tâche chaque minute ou deux dans une application console.
J'ai besoin de garder Main()
cours d'exécution dans une "boucle infinie", tandis qu'un timer déclenche l'événement qui va faire le travail. Je tiens à garder Main()
avec l'impact le plus faible sur le CPU.
Quelles sont les méthodes que vous proposez. Sleep()
peut être ok, mais comme je l'ai déjà mentionné, cela pourrait indiquer un insensible fil pour le système d'exploitation.
PLUS TARD EDIT:
Je veux expliquer mieux ce que je suis à la recherche d':
-
- Je besoin d'une application console pas de service Windows. Console les applications peuvent simuler les services Windows sur Windows Mobile 6.x systèmes avec le Compact Framework.
-
J'ai besoin d'un moyen de garder l'application en vie aussi longtemps que l'appareil Windows Mobile est en cours d'exécution.
-
Nous savons tous que l'application de console s'exécute tant que ses statique de la fonction main() s'exécute, j'ai donc besoin d'un moyen de prévenir la fonction main() de sortie.
-
Dans des situations particulières (comme: mise à jour de l'application), j'ai besoin de demander l'application d'arrêter, j'ai donc besoin de boucle à l'infini et de test pour certains sortie de la condition. Par exemple, c'est pourquoi
Console.ReadLine()
n'est d'aucune utilité pour moi. Il n'y a pas de sortie contrôle de condition. -
Concernant ce qui précède, je veux encore la fonction main() en tant que ressource conviviale que possible. Laissez asside l'empreinte de la fonction qui vérifie la condition de sortie.
Thread.Sleep(0)
est probablement une bonne chose- Est-ce une application winforms?
- Pourquoi n'avez-vous pas un
Timer
? Sleep(0)
abandonne le reste de l'actuelle tranche de temps, mais elle ne conduit pas à 100% d'utilisation CPU. De sorte qu'il ne fonctionne pas ici.- Pouvez-vous élaborer sur le "peut indiquer une application qui ne répond pas au système d'exploitation" problème? Êtes-vous sûr que c'est un problème dans une application console?
- Aussi l'OS ne se soucie pas de répondre threads. Il se soucie de répondre fils qui possèdent une fenêtre. Et cela ne semble pas être le cas ici.
Sleep(0)
résultats dans "ce % n'est pas utilisé ailleurs" qui est parfois assez cool - en particulier lors de la prise d'une application qui utilise des 'ressources' de faire son travail (par exemple, le projet SETI@Home ou quelque chose serait un cas d'utilisation).- Pour SETI et autres applications similaires, je serais tout simplement de réduire la priorité de mon processus/thread afin de ne pas obtenir de temps CPU quand quelqu'un d'autre en a besoin.
- Quelle est votre Principale méthode de besoin dans cette "boucle infinie"? Peut-être principale peut le coup d'envoi de la minuterie, puis appeler la Console.ReadLine().
Vous devez vous connecter pour publier un commentaire.
Pour éviter le débordement de la boucle de simplement utiliser un
WaitHandle
. Pour permettre le processus d'être sorti entre le monde extérieur et l'utilisation d'unEventWaitHandle
avec une chaîne unique. Ci-dessous est un exemple.Si vous démarrez pour la première fois, c'est simple imprime un message toutes les 10 secondes. Si vous commencez dans le temps, une deuxième instance du programme, il devra en informer l'autre processus gracieusement sortie et quitte de lui-même immédiatement. L'utilisation du PROCESSEUR pour cette approche: 0%
while(true)
style boucle à la moyenne ~0.04% d'utilisation du PROCESSEUR avec un WaitHandle.waitHandle.Set()
à partir d'un autre thread ou processus, puis recréer la poignée avecnew EventWaitHandle(...)
et faire la boucle while de nouveau.System.Threading.Timer
. Les paramètres sont le délégué qui doit être appelée, les paramètres de la méthode, combien de temps attendre jusqu'à ce que le premier appel et combien de temps entre tous les appels suivants devraient être.Vous pouvez utiliser Système.Le filetage.Minuterie Classe qui fournit de la capacité d'exécution de rappel asynchrone dans une période de temps donnée.
Comme alternative, il est Système.Les minuteries.Minuterie classe qui expose Événement Écoulé qui soulève lors d'une période de temps est écoulé.
Environment.TickCount
,Thread.Sleep
, etc.) - et, oups, c'est de 15,6 ms: stackoverflow.com/questions/3744032/...Environment.TickCount
sur ma machine a une résolution de 20~30ms. msdn.microsoft.com/en-us/library/ms686298(v=vs. 85).aspxPourquoi voulez-vous tolérer l'utilisation d'une boucle infinie? Pour cet exemple, le réglage du programme jusqu'en tant que tâche planifiée, afin d'être exécuté à chaque minute, pas plus économique?
Pourquoi ne pas vous écrire une petite application et de l'utilisation du système planificateur de tâches à exécuter à chaque minute, heure, etc...?
Une autre option serait d'écrire un Service Windows qui s'exécute en arrière-plan. Le service pourrait utiliser une Alarme simple classe comme suit sur MSDN:
http://msdn.microsoft.com/en-us/library/wkzf914z%28v=VS.90%29.aspx#Y2400
Vous pouvez l'utiliser pour déclencher périodiquement votre méthode. En interne, cette Alarme classe utilise une minuterie:
http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx
Il suffit de régler la minuterie d'intervalle correctement (par exemple, 60000 millisecondes) et il va déclencher l'événement Écoulée périodiquement. Associer un gestionnaire d'événement pour l'événement Écoulé pour accomplir votre tâche. Pas besoin de mettre en œuvre une "boucle infinie" juste pour garder l'application en vie. Ce sont gérées par le service.
Je l'ai fait pour une application qui avait pour traiter les fichiers qu'ils ont été abandonnés sur un dossier. Votre meilleur pari est d'une minuterie (comme l'a suggéré) avec une Console.ReadLine() à la fin de la "main" sans le mettre dans une boucle.
Maintenant, votre préoccupation à propos de demander à l'application de s'arrêter:
Je l'ai aussi fait par le biais de certains rudimentaire "fichier" moniteur. Il suffit de créer le fichier "quit.txt" dans le dossier racine de l'application (par mon programme ou une autre application qui pourrait demande à l'arrêt) fera la fermeture de l'application. Semi-code:
La OnNewFile pourrait être quelque chose comme ceci:
Maintenant, vous avez mentionné que c'est (ou pourrait être) pour une application mobile? Vous pourriez ne pas avoir le fichier system watcher. Dans ce cas, peut-être vous avez juste besoin de "tuer" le processus (vous avez dit "Dans des situations particulières (comme: mise à jour de l'application), j'ai besoin de demander l'application de l'arrêt". Celui qui le "demandeur" à l'arrêt il est, il suffit de tuer le processus)
Il me semble que vous souhaitez Main() pour entrer une interruptable boucle. Pour ce faire, plusieurs threads doivent être impliqués quelque part (ou de votre boucle doit interroger périodiquement; je ne suis pas discuter de cette solution ici). Soit un autre thread dans la même application, ou d'un fil dans un autre processus, doit être en mesure de signal de votre Main() de la boucle qu'il devrait mettre fin à l'.
Si cela est vrai, alors je pense que vous voulez utiliser un ManualResetEvent ou un EventWaitHandle . Vous pouvez attendre de cet événement jusqu'à ce qu'il est marqué (et la signalisation devra être faite par un autre thread).
Par exemple:
Vous pouvez utiliser
Begin-/End-Invoke
céder à d'autres threads. E. g.Que vous pouvez l'utiliser en tant que tel:
Cette habitude de 60% d'un core sur ma machine (complètement vide de la boucle). Alternativement, vous pouvez utiliser cette (Source) code dans le corps de la boucle:
Que 20% d'un core sur ma machine.
Pour exposer sur un commentaire CodeInChaos fait:
Vous pouvez définir un priorité du thread. Les Threads sont prévues pour l'exécution en se basant sur leur priorité. L'algorithme d'ordonnancement utilisé pour déterminer l'ordre d'exécution du fil varie avec chaque système d'exploitation. Tous les threads par défaut "à la normale" la priorité, mais si vous définissez votre boucle à faible; il ne devrait pas voler du temps à partir de fils normal.
La Minuterie approche est probablement votre meilleur pari, mais puisque vous parlez de Fil.Le sommeil est intéressant Fil de discussion.SpinWait ou SpinWait struct alternative pour des problèmes similaires qui peut être parfois mieux que de courtes Fil.Le sommeil des invocations.
Voir aussi cette question: Quel est le but de Fil.SpinWait méthode?
Beaucoup de "avancée" de réponses ici, mais de l'OMI simplement à l'aide d'un Fil.Sommeil(lowvalue) devrait suffire pour la plupart.
Minuteurs sont aussi une solution, mais le code derrière une minuterie est aussi une infinité de boucle - je suppose - que les feux de votre code écoulé intervalles, mais ils ont le bon débordement de configuration en boucle.
Si vous avez besoin d'un grand sommeil, vous pouvez le couper en petits dort.
Donc quelque chose comme ceci est un simple et facile à 0% de CPU solution pour un non-INTERFACE de l'app.
Concernant la façon dont le système d'exploitation détecte si l'application ne répond pas. Je ne sais pas du tout les autres tests que sur l'INTERFACE utilisateur des applications, où il existe des méthodes pour vérifier si le thread d'INTERFACE utilisateur processus code de l'INTERFACE utilisateur. Fil dort sur l'INTERFACE utilisateur pourra facilement être découvert. Les Fenêtres "l'Application ne répond pas" utilise une simple méthode native "SendMessageTimeout" pour voir de détecter si l'application dispose d'un unresponse de l'INTERFACE utilisateur.
Tout l'infini de la boucle sur une INTERFACE utilisateur application doit toujours être exécuté dans un thread séparé.
De garder les applications de console en cours d'exécution juste ajouter un
Console.ReadLine()
à la fin de votre code dansMain()
.Si l'utilisateur ne devrait pas être en mesure de mettre fin à l'application, vous pouvez le faire avec une boucle comme suit:
Environment.Exit(0)
.