Question

À l'heure actuelle, j'ai un grand nombre de calculs de C # (appels de méthode) résidant dans une file d'attente qui sera exécutée de manière séquentielle. Chaque calcul utilisera un service de haute latence (réseau, disque ...).

J'allais utiliser coroutines Mono pour permettre le calcul suivant dans la file d'attente de calcul de continuer alors qu'un calcul précédent attend le service de temps d'attente pour revenir. Cependant, je préfère ne pas dépendre de Mono coroutines.

Y at-il un modèle de conception qui est implémentable dans le plus pur C # qui me permettra de traiter des calculs supplémentaires en attendant des services de haute latence de retour?

Merci

Mise à jour:

Je dois exécuter un grand nombre (> 10000) des tâches et chaque tâche utiliserai un service de haute latence. Sous Windows, vous ne pouvez pas créer de threads que beaucoup.

Mise à jour:

En fait, je besoin d'un modèle de conception qui émule les avantages (comme suit) de tasklets dans Stackless Python ( http: // www.stackless.com/ )

  1. # énorme de tâches
  2. Si une tâche bloque la tâche suivante dans la file d'attente exécute
  3. Aucun cycle cpu perdu
  4. Minimal commutation surcharge entre les tâches
Était-ce utile?

La solution

Vous pouvez simuler microthreading coopérative en utilisant IEnumerable. Malheureusement, cela ne fonctionne pas avec les API de blocage, vous devez donc trouver des API que vous pouvez Poll, ou qui ont callbacks que vous pouvez utiliser pour la signalisation.

Considérons une méthode

IEnumerable Thread ()
{
    //do some stuff
    Foo ();

    //co-operatively yield
    yield null;

    //do some more stuff
    Bar ();

    //sleep 2 seconds
    yield new TimeSpan (2000);
}

Le compilateur C # va déballer ceci dans une machine d'état -. Mais l'apparence est celle d'une MicroThread coopérative

Le modèle est assez simple. Vous mettre en œuvre un « planificateur » qui maintient une liste de tous les IEnumerators actifs. Comme il fait défiler la liste, il « runs » chacun utilisant MoveNext (). Si la valeur de MoveNext est fausse, le fil est terminé, et le planificateur supprime de la liste. S'il est vrai, le planificateur accède à la propriété actuelle pour déterminer l'état actuel du fil. Si c'est un TimeSpan, le fil souhaite dormir, et le planificateur a déplacé sur une file d'attente qui peuvent être vidées de nouveau dans la liste principale lorsque les plages temporelles du sommeil ont pris fin.

Vous pouvez utiliser d'autres objets de retour pour mettre en œuvre d'autres mécanismes de signalisation. Par exemple, définir une sorte de WaitHandle. Si le fil donne un de ceux-ci, il peut être déplacé vers une file d'attente jusqu'à ce que la poignée est signalée. Ou vous pourriez soutenir WaitAll en donnant une série de poignées d'attente. Vous pouvez même mettre en œuvre les priorités.

Je l'ai fait d'une simple mise en œuvre de ce planificateur dans environ 150LOC mais je ne l'ai pas eu tour à bloguer le code encore. Il était pour notre emballage PhyreSharp de PhyreEngine (qui ne sera pas public), où il semble assez bien fonctionner pour contrôler quelques centaines de personnages dans l'une de nos démos. Nous avons emprunté le concept du moteur Unity3D - ils ont des documents en ligne qui expliquent d'un point de vue utilisateur

.

Autres conseils

Je vous recommande d'utiliser le pool de threads pour exécuter des tâches multiples de votre file d'attente à la fois par lots faciles à gérer en utilisant une liste de tâches actives qui se nourrit de la file d'attente des tâches.

Dans ce scénario principal thread de travail sauterait d'abord les tâches N de la file d'attente dans la liste des tâches actives à expédier à la piscine de fil (le plus probablement en utilisant

Vous devriez vraiment consulter la Concurrency et Coordination Runtime . L'un de leurs échantillons décrit exactement ce que vous parlez: vous appelez aux services de longue latence, et le CCR permet efficacement une autre tâche à exécuter pendant que vous attendez. Il peut gérer grand nombre de tâches, car il n'a pas besoin de lancer un fil pour chacun, bien qu'il utilisera tous vos cœurs si vous demandez à.

est-ce pas une utilisation classique de traitement multi-thread?

Jetez un oeil à des modèles tels que le réacteur

il écrit à utiliser Async IO pourrait être suffisante.

Cela peut conduire à nasy, difficile à code de débogage sans structure forte dans la conception.

Vous devriez jeter un oeil à ceci:

http://www.replicator.org/node/80

Cela devrait faire exactement ce que vous voulez. Il est un hack, cependant.

Un peu plus d'informations sur le modèle « réactif » (comme mentionné par une autre affiche) par rapport à une mise en œuvre .NET; alias "Linq aux événements"

http://themechanicalbride.blogspot.com /2009/07/introducing-rx-linq-to-events.html

-Oisin

En fait, si vous utilisez un fil pour une tâche, vous perdrez le jeu. Pensez à pourquoi Node.js peut prendre en charge grand nombre de conections. L'utilisation d'un petit nombre de fils avec IO !!! async Async et attendent les fonctions peuvent aider à ce sujet.

foreach (var task in tasks)
{
    await SendAsync(task.value);
    ReadAsync(); 
}

SendAsync () et ReadAsync () sont des fonctions truquées à Async appel IO.

parallélisme Tâche est aussi un bon choisir. Mais je ne suis pas sûr que l'on est plus rapide. Vous pouvez tester les deux dans votre cas.

Oui, bien sûr, vous pouvez. Vous avez juste besoin de construire un mécanisme régulateur qui rappel sur un lambda que vous fournissez et entre dans une file d'attente. Tout le code que j'écris dans l'unité utilise cette approche et je ne jamais utiliser coroutines. J'enveloppe des méthodes qui utilisent coroutines tels que des trucs Web pour simplement débarrasser. En théorie, coroutines peut être plus rapide parce qu'il ya moins de frais généraux. En pratique, ils introduisent une nouvelle syntaxe à une langue pour faire une tâche assez trivial et de plus, vous ne pouvez pas suivre la trace de la pile correctement sur une erreur dans une co-routine parce que tout ce que vous verrez est -> Suivant. Vous devrez mettre en œuvre alors la possibilité d'exécuter les tâches dans la file d'attente sur un autre fil. Cependant, il y a des fonctions parallèles dans la dernière .net et vous écrirais essentiellement des fonctionnalités similaires. Il ne serait pas beaucoup de lignes de code vraiment.

Si quelqu'un est intéressé j'envoyer le code, ne l'ont pas sur moi.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top