Continuation de première classe en C # via C ++ interop ou une autre manière?

Nous avons une application C # multitâche très performante, quasi temps réel. Cette performance a été obtenue principalement grâce à la mise en œuvre en interne de tâches multitâches coopératives avec un planificateur développé à la maison. Ceci est souvent appelé micro-thread. 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 avons semble ne pouvoir être résolu que par des suites de première classe que C # ne prend pas en charge.

Plus précisément, le problème se pose dans 2 cas concernant des files d’attente. Chaque fois qu’une tâche particulière effectue un travail avant de placer un élément dans une queue. Et si la queue est pleine?

Inversement, une tâche différente peut s’acquitter de certaines tâches et doit ensuite extraire un élément d’une file d’attente. Et si cette queue est vide?

Nous avons résolu ce problème dans 90% des cas en liant les files d’attente à des tâches pour éviter que des tâches ne soient appelées si l’une de leurs files d’attente sortantes était saturée ou si la queue entrante était vide.

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

Le vrai problème se pose dans quelques cas extrêmes où il est impossible de faire l’une ou l’autre de ces solutions. L’idée dans ce scénario serait de sauvegarder l’état de la stack au point et de passer à une tâche différente afin qu’elle puisse effectuer le travail et réessayer ultérieurement la tâche en attente chaque fois qu’elle est capable de continuer.

Dans le passé, nous avons tenté de rappeler (de manière récursive) l’appel de la tâche en attente dans la planification afin d’autoriser les autres tâches à réessayer ultérieurement. Cependant, cela a conduit à 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 d’état de stack entre les threads. Mais maintenant, je n’arrive pas à trouver un exemple de code pour cela. De plus, il semble que cela prendra une complexité considérable pour bien faire les choses.

Quelqu’un a-t-il d’autres idées créatives sur la manière de basculer efficacement d’une tâche à l’autre et d’éviter les problèmes susmentionnés?

Existe-t-il d’autres hôtes CLR proposant cette fonctionnalité, commerciale ou autre? Existe-t-il une bibliothèque native complémentaire pouvant offrir une forme de continuité pour C #?

Il y a le CTP C # 5 , qui effectue une transformation du style continuation-pass sur les méthodes déclarées avec le nouveau mot-clé async , et des appels basés sur la poursuite-continuation lors de l’utilisation du mot-clé await .

Il ne s’agit pas en réalité d’une nouvelle fonctionnalité 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 des continuations. Les enregistrements d’activation pour les méthodes async sont placés sur le tas au lieu de la stack, ils ne sont donc pas liés à un thread spécifique.

Non, ne va pas au travail. 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 le C 5 proposera. Cela dit, vous ne pourrez probablement pas interrompre / reprendre des boucles / itérations d’ordre supérieur, ce que vous voulez vraiment des continuations reifiables à usage général.

Le mode Fibre a été supprimé de la v2 du CLR en raison de problèmes liés au stress. Voir:

  • Le mode fibre est parti …
  • Fibres et le CLR
  • Question aux experts du CLR: support du mode fibre dans l’hébergement

A ma connaissance, le support fibre n’a pas encore été rajouté, mais il peut être ajouté à la lecture des articles ci-dessus (toutefois, le fait que rien ne soit mentionné depuis 6 ou 7 ans me laisse croire que c’est peu probable).

La prise en charge des fibres FYI était censée être un moyen pour les applications existantes utilisant des fibres (telles que SQL Server) d’héberger le CLR de manière à leur permettre d’optimiser les performances, et non 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 souhaite héberger le CLR, les API d’hébergement gérées fournissent le moyen pour le CLR de “fonctionner correctement” avec votre application. Une bonne source d’information à ce sujet serait la documentation de l’API d’hébergement géré ou la manière dont SQL Server héberge le CLR, qui contient plusieurs articles très instructifs.

Prenez également une lecture rapide de fils, fibres, stacks et espace d’adressage .

En fait, nous avons décidé de suivre cette direction. Nous utilisons le modèle Observer avec Message Passsing. Nous avons construit une bibliothèque maison pour gérer toutes les communications entre “agents” similaires à un processus Erlang. Plus tard, nous envisagerons d’utiliser AppDomains pour encore 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 multi-cœur et dissortingbué extrêmement fiable.

La solution à votre problème consiste à utiliser des algorithmes sans locking permettant la progression d’au moins une tâche sur l’ensemble du système. Vous devez utiliser un assembleur en ligne dépendant de la CPU pour vous assurer que vous êtes atomique CAS (compare-and-swap). Wikipedia propose un article ainsi que des modèles décrits dans le livre de Douglas Schmidt intitulé “Architecture logicielle orientée modèles, Modèles pour objects concurrents et en réseau”. Je ne sais pas tout de suite comment vous allez procéder dans le cadre du réseau de points.

Une autre façon de résoudre votre problème consiste à utiliser le modèle publication-abonné ou les pools de threads possibles.

Espérons que cela a été utile?