2012-08-31 4 views
3

Je développe une application client/serveur WCF et le client appelle le serveur de manière asynchrone en encapsulant l'appel au Task.Factory.StartNew et en utilisant une continuation pour appeler un délégué fourni par l'utilisateur au retour de l'appel WCF. L'opération du serveur effectue (entre autres) des E/S série avant de renvoyer une réponse au client. Le service utilise également un BlockingCollection pour mettre en file d'attente ces demandes, s'assurant qu'elles sont exécutées une à la fois pour éviter les conflits de port série. En l'état, l'application fonctionne parfaitement, même lorsque le client envoie une série de requêtes au serveur en succession rapide. Maintenant, l'application peut également être configurée pour fonctionner en mode "direct", où le client référence directement les assemblages côté serveur (pour des raisons de performances, si le client et le serveur sont sur le même PC). Dans ce scénario, le client utilise une instance de la classe de service (plutôt qu'un proxy créé par ChannelFactory) et appelle sa méthode d'opération directement, en utilisant le même assistant asynchrone Task.Factory.StartNew.Étrangeté multithread

Dans ce mode "direct", je trouve que l'exécution côté serveur semble se dérouler lentement (il manque des données de port série), comme si elle était interrompue d'une manière ou d'une autre. Je peux "réparer" en changeant la tâche côté client pour utiliser TaskCreationOptions.LongRunning. Malheureusement, cela casse alors l'application en "mode WCF", qui semble souffrir des mêmes problèmes de lenteur.

Maintenant, je pourrais simplement inclure le TaskCreationOptions (ou pas) en fonction du "mode" que l'application utilise, mais je voudrais comprendre pourquoi cela se produit en premier lieu. Des idées?

Modifier: Je remarque que le problème lors du démarrage de l'application lorsque le client envoie une douzaine de requêtes au serveur l'un après l'autre, dans une boucle for. Après cela, le client interroge le serveur toutes les demi-secondes - ceci n'est pas affecté par le problème, et les deux autres minuteurs de threads qui exécutent le côté client et côté serveur (dont un se déclenche toutes les 65ms!). Je suis tombé sur un article indiquant que le pool de threads créera de nouveaux threads jusqu'à ce que le nombre minimum de threads soit atteint, après quoi il limite le nombre de threads créés à un par 500 millisecondes. Cela correspond aux symptômes de mon problème car je vois la lenteur frapper environ toutes les demi-seconde. Je vais refactoriser mon code côté client pour éviter de frapper le serveur tant de fois de suite, ce qui est dommage. Je voulais vraiment déclencher toutes ces requêtes l'une après l'autre, puis gérer les résultats dans les délégués de rappel une fois qu'ils avaient été traités par le serveur. Mais avec cette fonctionnalité "thread" il semble que je ne peux pas faire cela.

+1

Première spéculation sauvage qui vient à l'esprit est que cette classe proxy sur le côté direct fait des choses en coulisses - encore inconnu - que la version de l'instance directe ne l'est pas. C'est là que je commencerais à chercher, au moins ... –

+0

Pourriez-vous partager une instance d'un objet entre votre client/serveur? En mode WCF, vous ne partagerez pas l'instance, en mode direct, vous pourriez l'être, et vous pourriez avoir un problème avec cela? – jasper

+0

@ jasper le lien est fait à travers un projet "facade" - le client fait référence à cet assembly mais pas directement au serveur. –

Répondre

0

Vous pouvez exécuter des outils de performance ou attacher des minuteurs pour savoir où se trouvent les goulots d'étranglement. Vous pouvez également utiliser le mode WCF sur un canal nommé. (http://msdn.microsoft.com/en-us/library/ms733769.aspx)

1

Si le passage à LongRunning le résout, cela implique que lorsque LongRunning n'est pas défini, le framework de tâche choisit d'utiliser le pool de threads, ou peut-être même pas utiliser un thread séparé du tout.

+0

Il est étrange car l'opération de service met simplement la requête en attente dans un BlockingCollection et retourne très rapidement. Puissant pourquoi je devrais spécifier LongRunning pour le faire fonctionner.Le côté serveur utilise un certain nombre de threads/tâches d'arrière-plan, donc peut-être que l'encapsulation de tâche asynchrone côté client interfère d'une certaine manière. –

+0

@Andrew Je suis aussi intéressé que vous à voir quelle est la source ultime du problème, mais si l'opération de service se termine si rapidement, est-ce que le client * doit * le lancer en utilisant une tâche? Que se passe-t-il si le client l'exécute directement sur son thread actuel? – shambulator

+0

@shambulator tout fonctionne bien si je viens d'appeler l'opération de manière synchrone. J'ai probablement été si occupé à essayer de résoudre le problème en utilisant le code asynchrone existant que je n'avais pas pensé à cela comme une solution. Je suppose que le seul problème serait que le service soit étendu à l'avenir pour inclure des opérations qui ne sont pas si éphémères. Peut-être que c'est l'un de ces "je vais traverser ce pont quand je viens à lui" choses ... –