11
votes

Quel est le moyen le plus efficace de la CPU de "perdre du temps" dans un fil?

J'ai un certain nombre de threads (100) qui exécutent chacun pendant quelques secondes à la fois. Lorsqu'ils exécutent, ils passent une quantité importante de ce temps en attente d'une réponse d'un autre système (un périphérique série). Je suis conscient que l'exécution de 100 threads exécutant à la fois pourrait être un porc de ressource afin que je limite le nombre de threads qui puisse commencer à une fois.

Cela me survient bien qu'il doit y avoir de bonnes et de mauvaises façons d'attendre un événement externe à l'intérieur d'un fil. Est-ce que cette approche CPU-intensive ?: xxx

et cette approche rend cette approche le rend plus efficace ?: xxx

* Info supplémentaire *

L'environnement est x86 Windows XP. Le code de thread est une série d'interactions longues et impliquées avec un dispositif série, mais en général, il consiste à écrire des caractères à un port COM (à l'aide de la bibliothèque de série Asyncfree) et d'attendre que des caractères soient renvoyés en campant sur le tampon des caractères entrants et les traiter quand ils arrivent. J'imagine que la bibliothèque de série rend le périphérique lit et écrit. Le temps dans le fil peut être aussi long qu'une minute, ou aussi courte que quelques secondes, mais la majeure partie de cette période est consacrée à attendre que des personnages quittent le port, ou attendent les caractères de réponse (le taux de bauds est lent), D'où ma question sur la meilleure façon pour le fil se comporte pendant que cela attend. Actuellement, j'appelle dormir dans une boucle en attente de caractèresinbuffer pour devenir non nulle, traiter chaque caractère lorsqu'il arrive et quitte le fil lorsque j'ai la réponse complète. Donc, le code ressemble plus à (ignorer la manipulation des délais d'expiration, etc.): xxx


13 commentaires

Veuillez indiquer votre système d'exploitation, cela pourrait être pertinent.


Cela dépend de ce que la boucle fait. Pouvez-vous fournir du code?


@MARCUSADAMS: TOUTE BOUCLE N'AFFAIRE PAS SON TIMESLICE AUX TIXELLES AUX OS OU D'ATTENTION D'UN OBJECTIF D'ÉVÉNEMENT / SYNC UTILISERA TOUT LE TEMPS DE LA CPU que le système d'exploitation sera mis à la disposition.


Si vous ne voyez pas votre utilisation de la CPU à 100%, il vous semble que vous n'avez aucun problème. Sans voir de vrai code, il est difficile de dire plus. jusqu'à ce que la réponse est arrivée est la clé. Qu'est-ce que cela fait réellement? Est-ce un appel de blocage?


@RossMCM: Il devrait y avoir un moyen pour le fil d'attendre une notification du système d'exploitation qu'une réponse soit disponible plutôt que de sondage pour cela.


@Afrazier, dit à l'Op que. C'est pourquoi je demande.


@Marcusadams, Afrazier. Merci pour vos réponses. Plus d'informations ajoutées à la question.


Sleep (0) Indique au planificateur Quel fil d'appel n'a pas besoin de restes de Current Timeslice et demande le prochain programme disponible. Donc, vous obtiendrez une réponse plus rapide opposée à dormir (20) et éviterons la gravure de processeur non ignifuge avec Spinlock générique.


Mais vous devriez vraiment examiner les opérations d'attente et / ou au chevauchement à cette fin.


@Pemature je soupçonne que la bibliothèque de ports COM sous-jacente utilise WaitFaVente (c'est là que les threads semblent être bloqués lorsque je regarde des décharges de MakeXcept)


@Rossmcm Si vos discussions bloquent déjà, vous n'avez probablement rien à faire.


TBH, votre question pourrait faire avec quelques explications supplémentaires. OK, vous avez 100 threads qui attendent des caractères sur un système de file d'attente tampon FIFO. Lorsque l'événement APRO RXDATA est tiré par le fil de réception APRO, comment connaissez-vous laquelle des 100 files d'attente pour pousser le RX. caractères sur? Existe-t-il un autre protocole de série de niveau inférieur qui bloque ce qui bloque le flux de série dans des messages / paquets, ou est l'un des 100 threads autorisés à prendre le contrôle du port à tout moment, à effectuer une échange de protocole, puis de «libération» Le port? Désolé, je n'ai pas de compréhension globale de la façon dont votre système fonctionne.


@Martin. Il y a jusqu'à 256 canaux, chacun avec leur propre port / FIFO, etc. Il est possible que tous les 256 canaux se déclenchent ensemble (mais à l'heure actuelle, je l'ai manifesté à 5-10 ou plus). Tous les canaux sont indépendants et n'auront jamais à attendre l'un de l'autre, bien que leurs événements à heure puisse arriver ensemble dans le fil principal et seront traités «en série», bien que cette charge de traitement ne soit pas excellente.


3 Réponses :


7
votes

Si le fil est vraiment en attente avec quelque chose comme une attente de servirforject, qui n'utilise pas de temps de processeur, il n'ya aucune raison de mettre un retard dans le fil avec dormir.

Votre utilisateur n'attend pas sur le thread pour être réactif, il n'utilise pas de temps de processeur, et d'autres threads ne seront pas bloqués, il n'y aurait donc aucune raison de mettre le fil à dormir.

Comme David Heffernan a indiqué dans son commentaire, s'il n'utilise pas 100% de votre CPU maintenant, il n'y a pas de problème.

Vous pouvez utiliser le sommeil () si vous étiez un seul fileté et que vous deviez répondre de temps à autre à l'utilisateur entre attendre sur le port série pour répondre.

En outre, avoir un sommeil de fil ne le rendrait pas plus efficace. Cela donnerait simplement des cycles de processeur à d'autres threads.

Jetez un coup d'oeil à Sleep (0) en tant que moyen efficace de la CPU de "gaspillage de temps" dans un fil.


6 commentaires

Aussi, avoir un sommeil de fil ne le rendrait pas plus efficace. Cela donnerait simplement des cycles de processeur à d'autres threads. N'est-ce pas le point? Si je mettais mon fil de dormir à 20 ms et le traitement de rendement à d'autres threads, cela ne rend pas plus de CPU à la disposition des autres threads / autres processus? Si j'ai 10000 threads et ils ont tout simplement entré dans un état de sommeil (10000), quelle est leur utilisation combinée de la CPU?


@Rossmom, si je suis dans un convoi, arrêtez mon camion pour laisser les autres passer n'augmenter l'efficacité. La même quantité de travail doit être effectuée. C'est tout simplement plus poli. Si j'arrête mon camion quand il n'y a personne à laisser passer, je perds du temps. Si 10000 threads dort, techniquement, ils utilisent 0 utilisation de la CPU, bien que le fil du système d'exploitation (planificateur) ait beaucoup de travail à faire et si vous manquez de RAM, vous allez certainement ralentir. Utiliser Sleep (0) obtiendra tout le plus tôt possible tout en étant toujours poli. Dormir (0) est plus efficace que le sommeil (200), car le temps est également une ressource.


Ok, donc je comprends maintenant que le sommeil (0) dit efficacement «passer à autre chose, rien à faire ici», donc si je vous tiens à mon architecture actuelle de limiter le nombre de threads pouvant commencer à dix et remplacer mon sommeil (20) En sommeil (0), j'aurai une situation qui a une faible latence et une faible utilisation de la CPU?


@RossMCM SLEEP (0) ne donnera que donner uniquement s'il existe un fil prêt à exécuter en attente. Sinon c'est un nop.


@rossmcm, avec sommeil (0) au lieu de sommeil (20), vous aurez une faible latence, mais vous êtes assuré d'une utilisation supérieure de la CPU alors qu'il y a du travail à faire. L'utilisation du processeur n'est pas mauvaise. Si personne d'autre n'utilise la CPU, pourquoi pas vous? Dormir (0) gardera l'ordinateur sensible à d'autres processus, ce qui permet de garder l'UI réagissant et permettra à l'utilisateur de continuer à regarder leur film ou de surfer sur le Web pendant que votre programme est exécuté. Si vous voulez intentionnellement, l'utilisateur attendait plus longtemps avec le sommeil (20) pour qu'ils ne voient pas la PCI de la CPU, c'est votre prérogative. Je préfère qu'ils pensent que leur ordinateur est lent au lieu de mon programme.


Dormir (0) ne cède pas à d'autres applications, il cède à d'autres threads prêts de la même priorité, s'il en existe. Si vous avez 100 threads avec une boucle SLEEP (0) et aucun autre appels de blocage, il y aura 100 threads prêts. Si une autre application à threads unique est en cours d'exécution et en essayant de progresser, son thread prêt aura le même processeur que les 100 threads de votre application, c'est-à-dire. 1/101 de la CPU disponible. Comme d'autres ont affiché, tout dépend de la vérification des blocs de caractères disponibles ou non. Si c'est le cas, il n'ya pas de point de sommeil (rien) - commencez simplement. Si cela ne le fait pas, alors il devrait!



2
votes

Le moyen le plus efficace d'empêcher un thread d'utiliser le temps de CPU est de la mettre en "mode d'attente".

Je n'utilise pas du tout Delphi, mais il semble que les fondamentaux de ceux-ci soient là. Voir "Chapitre 11. Synchronisants et événements" et plus précisément < un href = "http://www.eonllash.com/tatudials/multhreading/martinharvey1.1/ch11.html#event%20Simulation%20utilisation%20Semaphores". rel = "nofollow"> "simulation d'événement utilisant des sémaphores" .

Si vous souhaitez attendre sans utiliser de CPU, utilisez Wallforevent :

L'état du signal de l'événement est examiné. S'il indique que l'événement est signalé, le sémaphore interne est signalé et le nombre de fils bloqués sur le sémaphore est décrémenté. Le nombre de fils bloqués est ensuite incrémenté et une attente est effectuée sur le sémaphore interne.

S'il s'agit d'E / S liés, alors les choses fonctionnent un peu différentes. Si c'est une prise, il peut être déjà bloqué, s'il s'agit d'E / S asynchrone, vous pouvez utiliser un sémaphore et WaitForevent et ainsi de suite.

in .NET Il y a le moniteur.wait , moniteur.signal , manuelleResetevent , compte-comtedlatch , etc ., Mais je ne sais pas quelles sont les choses équivalentes à Delphes.


0 commentaires

2
votes

Je ne peux pas parler pour les capacités de l'AsyncPree, mais dans la programmation générale du port dans Windows prend en charge les E / S chevauchées, vous pouvez donc attendre efficacement une notification lorsque les données arrivent à l'aide de la fonction WEETCOMMEvent () avec L'un des waitfor ... () famille de fonctions, tels que waitforsingleObject () . Le thread peut être mis dans un état de veille jusqu'à ce que la notification soit des problèmes, au moment où il "se réveille" de lire du port jusqu'à ce qu'il n'y ait rien de plus en lecture, il peut revenir au sommeil jusqu'à ce que le prochain notify.


0 commentaires