Question

J'écris un service Web ASP.NET en C # doté d'une fonction DoLookup (). Pour chaque appel de la fonction DoLookup (), j'ai besoin de mon code pour exécuter deux requêtes distinctes: une sur un autre service Web sur un site distant et une sur une base de données locale. Les deux requêtes doivent être terminées avant que je puisse compiler les résultats et les renvoyer comme réponse à la méthode DoLookup. Le problème que je traite est que je veux rendre cela aussi efficace que possible, à la fois en termes de temps de réponse et d'utilisation des ressources sur le serveur Web. Nous attendons plusieurs milliers de requêtes par heure. Voici un aperçu approximatif de ce que j’ai eu jusqu’à présent sur C #:

public class SomeService : System.Web.Services.WebService
{
    public SomeResponse DoLookup()
    {
        // Do the lookup at the remote web service and get the response 
        WebResponse wr = RemoteProvider.DoRemoteLookup();   

        // Do the lookup at the local database and get the response
        DBResponse dbr = DoDatabaseLookup();

        SomeResponse resp = new SomeResponse( wr, dbr);

        return resp;
    }
}

Le code ci-dessus fait tout de manière séquentielle et fonctionne très bien, mais je souhaite maintenant le rendre plus évolutif. Je sais que je peux appeler la fonction DoRemoteLookup () de manière asynchrone (RemoteProvider utilise les méthodes BeginRemoteLookup / EndRemoteLookup) et que je peux également effectuer la recherche de base de données de manière asynchrone à l'aide des méthodes BeginExecuteNonQuery / EndExecuteNonQuery.

Ma question (enfin) est la suivante: comment puis-je lancer simultanément la recherche de service Web distant ET la recherche de base de données sur des threads distincts et m'assurer qu'ils sont tous deux terminés avant de renvoyer la réponse?

La raison pour laquelle je souhaite exécuter les deux requêtes sur des threads distincts est que les deux temps de réponse sont potentiellement longs (1 ou 2 secondes) et que je souhaite libérer les ressources du serveur Web afin de gérer d'autres requêtes pendant son exécution. en attente de réponses. Remarque supplémentaire: la recherche de service Web à distance s'exécute actuellement de manière asynchrone. Je ne voulais tout simplement pas créer trop de confusion dans l'exemple ci-dessus. Ce qui me pose problème, c’est d’obtenir à la fois la recherche de service à distance ET la recherche dans la base de données démarrée en même temps et de déterminer quand ils ont tous les deux terminé.

Merci pour vos suggestions.

Était-ce utile?

La solution

Vous pouvez utiliser une paire de AutoResetEvents , un pour chaque thread. À la fin de l'exécution du fil, vous appelez AutoResetEvents.Set () pour déclencher l'événement.

Après avoir créé les threads, vous utilisez WaitAll () avec les deux AutoResetEvents. Le thread sera bloqué jusqu'à ce que les deux événements soient définis.

L’avertissement à cette approche est que vous devez vous assurer que la méthode Set () est garantie, sinon vous bloquerez pour toujours. De plus, assurez-vous qu'avec les threads, vous gérez correctement les exceptions ou vous causerez par inadvertance davantage de problèmes de performances lorsque des exceptions non gérées entraînent le redémarrage de votre application Web.

MSDN contient un exemple de code relatif à l'utilisation d'AutoResetEvent.

Autres conseils

Voir Méthodes de service Web XML asynchrones , Comment: créer des méthodes de service Web asynchrones et Comment: chaîner des appels asynchrones avec une méthode de service Web .

Mais notez le premier paragraphe de ces articles:

  

Ce sujet est spécifique à une technologie héritée. Les services Web XML et les clients de services Web XML doivent maintenant être créés à l'aide de Windows Communication Foundation (WCF) .

BTW, il est important de procéder comme indiqué dans ces articles, car cela libère le thread de travail ASP.NET pendant l'exécution de la tâche de longue durée. Sinon, vous pouvez bloquer le thread de travail, l'empêcher de traiter d'autres requêtes et avoir un impact sur l'évolutivité.

En supposant que vous puissiez avoir une fonction de rappel pour la requête Web et la consultation de la base de données, un résultat similaire peut fonctionner

bool webLookupDone = false;
bool databaseLookupDone = false;

private void FinishedDBLookupCallBack()
{
    databaseLookupDone = true;
    if(webLookupDone)
    {
        FinishMethod();
    }
}

private void FinishedWebLookupCallBack()
{
    webLookupDone = true;
    if(databaseLookupDone)
    {
        FinishMethod();
    }
}

Je suppose que je n'ai pas assez de représentants pour faire voter ou commenter. C’est donc un commentaire sur la réponse de John Saunders et le commentaire d’Alan à ce sujet.

Vous voulez certainement aller avec la réponse de John si vous êtes préoccupé par l'évolutivité et la consommation de ressources.

Deux considérations sont à prendre en compte ici: accélérer une requête individuelle et permettre à votre système de gérer efficacement de nombreuses requêtes simultanées. Les réponses précédentes de Alan et John obtiennent ces résultats en effectuant les appels externes en parallèle.

La dernière, et il semble que ce soit votre principale préoccupation, est obtenue en ne bloquant aucun fil, nulle part, c’est-à-dire la réponse de John.

Ne créez pas vos propres discussions. Les threads coûtent chers et le Threadpool IO contient déjà de nombreux threads qui gèrent vos appels externes pour vous si vous utilisez les méthodes asynchrones fournies par le framework .net.

La méthode Web de votre service doit également être asynchrone. Sinon, un thread de travail sera bloqué jusqu'à ce que vos appels externes soient terminés (il reste 1 à 2 secondes, même s'ils se déroulent en parallèle). Et vous ne disposez que de 12 threads par processeur traitant les requêtes entrantes (si votre machine.config est défini conformément à recommandation .) Ie vous seriez tout au plus capable de gérer 12 demandes simultanées (fois le nombre de CPU). Par contre, si votre méthode Web est asynchrone, Begin commencera à être renvoyé presque instantanément et le fil sera renvoyé au pool de threads de travail, prêt à traiter une autre demande entrante, pendant que vos appels externes sont en attente par le port d'achèvement IO, où ils seront être traités par les threads du pool de threads IO, une fois qu'ils sont renvoyés.

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