32 votes

C# first class continuation via C++ interop ou autre ?

Nous disposons d'une application C# multitâche très performante, quasiment en temps réel. Ces performances ont été obtenues principalement en implémentant le multitâche coopératif en interne avec un planificateur maison. Ce système est souvent appelé micro-threads. Dans ce système, toutes les tâches communiquent avec d'autres tâches via des files d'attente.

Le problème spécifique que nous rencontrons ne semble pouvoir être résolu que par des continuations de première classe, que le C# ne prend pas en charge.

Plus précisément, le problème se pose dans 2 cas traitant des files d'attente. Chaque fois qu'une tâche particulière effectue un travail avant de placer un élément dans une file d'attente. Que se passe-t-il si la file d'attente est pleine ?

À l'inverse, une autre tâche peut effectuer un travail et avoir ensuite besoin de retirer un élément d'une file d'attente. Et si cette file d'attente est vide ?

Nous avons résolu ce problème dans 90% des cas en liant les files d'attente aux tâches pour éviter que les tâches soient invoquées si l'une de leurs files d'attente sortantes est pleine ou si la file d'attente entrante est vide.

De plus, certaines tâches ont été converties en machines à états afin qu'elles puissent gérer si une file d'attente est pleine/vide et continuer sans attendre.

Le véritable problème se pose dans quelques cas limites où il n'est pas possible d'appliquer l'une ou l'autre de ces solutions. Dans ce cas, l'idée serait de sauvegarder l'état de la pile à ce moment-là et de passer à une autre tâche pour qu'elle puisse effectuer le travail, puis de relancer la tâche en attente dès qu'elle est en mesure de continuer.

Dans le passé, nous avons essayé de faire en sorte que la tâche en attente rappelle le planning (de manière récursive) pour permettre aux autres tâches de relancer la tâche en attente. Cependant, cela conduisait à trop de situations de "blocage".

Il y avait un exemple quelque part d'un hôte CLR personnalisé pour que les threads .NET fonctionnent réellement comme des "fibres", ce qui permet essentiellement de changer l'état de la pile entre les threads. Mais je n'arrive pas à trouver d'exemple de code pour cela. De plus, il semble qu'il faille une certaine complexité pour y parvenir.

Quelqu'un a-t-il d'autres idées créatives pour passer d'une tâche à l'autre efficacement et éviter les problèmes susmentionnés ?

Y a-t-il d'autres hôtes CLR qui offrent cela, commerciaux ou non ? Existe-t-il une bibliothèque native complémentaire qui puisse offrir une certaine forme de continuations pour C# ?

2voto

Jeffrey Hantin Points 19272

Il y a le C# 5 CTP qui effectue une transformation de type "continuation-passing" sur les méthodes déclarées avec le nouvel attribut async et les appels basés sur le passage à la suite lors de l'utilisation du mot-clé await mot-clé.

Il ne s'agit pas d'une nouvelle fonctionnalité du CLR, mais plutôt d'un ensemble de directives permettant au compilateur d'effectuer la transformation CPS sur votre code et d'une poignée de routines de bibliothèque permettant de manipuler et de planifier les continuations. Les enregistrements d'activation pour async sont placées sur le tas au lieu de la pile, de sorte qu'elles ne sont pas liées à un thread spécifique.

1voto

leppie Points 67289

Non, ça ne va pas marcher. C# (et même IL) est un langage trop complexe pour effectuer de telles transformations (CPS) de manière générale. Le mieux que vous puissiez obtenir est ce que C# 5 offrira. Cela dit, vous ne serez probablement pas en mesure de rompre/reprendre avec des boucles/itérations d'ordre supérieur, ce qui est vraiment ce que vous voulez des continuations réifiables d'usage général.

1voto

Justin Points 42106

Le mode fibre a été supprimé de la v2 du CLR en raison de problèmes sous contrainte, voir :

A ma connaissance, le support de la fibre n'a pas encore été ajouté, bien qu'à la lecture des articles ci-dessus, il soit possible de le faire. puede être ajouté à nouveau (cependant le fait que rien n'ait été mentionné depuis 6-7 ans sur le sujet me fait penser que c'est peu probable).

Pour votre information, la prise en charge des fibres était destinée à permettre aux applications existantes qui utilisent des fibres (comme SQL Server) d'héberger le CLR d'une manière qui leur permette de maximiser les performances, no comme une méthode permettant aux applications .Net de créer des centaines de threads. en bref, les fibres ne sont pas une solution miracle à votre problème. Toutefois, si vous avez une application qui utilise des fibres et que vous souhaitez héberger le CLR, les API d'hébergement géré permettent au CLR de "fonctionner agréablement" avec votre application. Une bonne source d'informations à ce sujet serait le site documentation sur l'API de l'hébergement géré ou pour examiner comment le serveur SQL héberge le CLR, il existe plusieurs articles très instructifs à ce sujet.

Jetez également un coup d'œil à Threads, fibres, piles et espace d'adressage .

1voto

Wayne Points 1468

En fait, nous avons décidé d'une direction à prendre avec ça. Nous utilisons le modèle Observer avec Message Passsing. Nous avons construit une bibliothèque maison pour gérer toute la communication entre les "Agents" qui sont similaires à un processus Erlang. Plus tard, nous envisagerons d'utiliser des AppDomains pour mieux séparer les agents les uns des autres. Les idées de conception ont été empruntées au langage de programmation Erlang, qui offre un traitement distribué et multicœur extrêmement fiable.

0voto

Damian Points 623

La solution à votre problème est d'utiliser des algorithmes sans verrou permettant la progression d'au moins une tâche à l'échelle du système. Vous devez utiliser un assembleur en ligne qui dépend du processeur pour vous assurer que vous êtes CAS (compare-and-swap) atomique. Wikipedia a un article ainsi que les modèles décrits dans le livre de Douglas Schmidt intitulé "Pattern-Oriented Software Architecture, Patterns for Concurrent and Networked Objects". Je ne vois pas très bien comment vous pourrez faire cela dans le cadre de Dotnet.

Une autre façon de résoudre votre problème consiste à utiliser le modèle de publication et d'abonnement ou d'éventuels pools de threads.

J'espère que cela a été utile ?

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