En parallèle ne fonctionne pas avec Entity Framework
J'ai une liste d'Id, et j'ai besoin d'exécuter plusieurs procédures stockées sur chaque ID.
Quand je suis à l'aide d'une boucle foreach, cela fonctionne bien, mais quand j'ai beaucoup de dossiers, cela fonctionne assez lent.
J'ai voulu convertir le code pour travailler avec EF, mais je suis une exception: "Le fournisseur sous-jacent a échoué à l'ouverture".
Je suis en utilisant ce code, à l'intérieur de la Parallèle.ForEach:
using (XmlEntities osContext = new XmlEntities())
{
//The code
}
Mais ça en jette toujours l'exception.
Une idée de comment puis-je l'utiliser en Parallèle avec EF? ai-je besoin de créer un nouveau contexte pour chaque procédure, je suis en cours d'exécution? J'ai autour de 10 procédures, donc je pense que c'est très mauvais pour créer 10 contextes, un pour chacun.
- Je ne suis pas un multithread gourou, mais si vous êtes à l'aide de transactions ou de lire/écrire devient verrouillé, vous ne pouvez pas obtenir de meilleures performances de le faire simplement en série.
- Je doute marteler l'a souligné sql server avec plus de fils ne va pas aider à la performance...
- Le sql est pas stressé du tout, c'est pourquoi je veux utiliser un parallèle. et il va sûrement courir plus vite.
- Sur la première boucle s'écraser ses
- Pourquoi voudriez-vous d'utiliser
.ToParallel()
sur EF? Il n'améliorera pas les performances. - Bonne chance que vous auriez tort. Pour mon application, je trouve que près de 6 tâches parallèles est idéal. Même qui est limitée par un conflit de verrouillage que l'équipe EF est à la recherche à
Vous devez vous connecter pour publier un commentaire.
Le sous-jacent de connexions de base de données que l'Entité Cadre à l'aide de pas thread-safe. Vous sera besoin de créer un nouveau contexte pour chaque opération sur un autre thread que vous allez effectuer.
Votre préoccupation quant à la façon de paralléliser l'opération est valide, et que de nombreux contextes vont coûter cher à ouvrir et à fermer.
Au lieu de cela, vous pourriez voulez inverser la façon dont votre pensée sur la parallélisation du code. Il semble que vous êtes en boucle sur un certain nombre d'éléments et puis l'appel de procédures stockées en série pour chaque élément.
Si vous le pouvez, créez un nouveau
Tâche<TResult>
(ouTâche
, si vous n'avez pas besoin d'un résultat) pour chaque procédure puis, dans ceTask<TResult>
, d'ouvrir un seul contexte, boucle sur tous les éléments, puis exécutez la procédure stockée. De cette façon, vous avez seulement un certain nombre de contextes égal au nombre de procédures stockées qui vous sont exécutés en parallèle.Supposons que vous avez un
MyDbContext
avec les deux procédures stockées,DoSomething1
etDoSomething2
, qui prennent une instance d'une classe,MyItem
.La mise en œuvre de la ci-dessus ressemblerait à quelque chose comme:
Si vous ne peut pas exécuter les procédures stockées en parallèle (chacun est dépendant de l'exécuter dans un certain ordre), alors vous pouvez toujours paralléliser les opérations, il est juste un peu plus complexe.
Vous regardez la création des partitions à travers vos articles (à l'aide de la statique
Créer
méthode sur leoutil de Partitionnement
de la classe). Cela vous donnera les moyens de le faireIEnumerator<T>
implémentations (remarque, c'est pasIEnumerable<T>
de sorte que vous ne pouvez pasforeach
dessus).Pour chaque
IEnumerator<T>
exemple, vous obtenez en retour, vous devez créer un nouveauTask<TResult>
(si vous avez besoin d'un résultat), et dans leTask<TResult>
corps, vous devez créer le contexte et ensuite parcourir les articles retournés par l'IEnumerator<T>
, l'appel de procédures stockées dans l'ordre.Qui ressemblerait à ceci:
EF n'est pas thread-safe, vous ne pouvez donc pas l'utiliser en Parallèle.
Prendre un coup d'oeil à Entity Framework et Multi threading
et ce l'article.
C'est ce que j'utilise et fonctionne très bien. Il prend par ailleurs en charge de la manipulation de l'erreur exceptions et dispose d'un mode debug qui rend beaucoup plus facile de suivre les choses vers le bas
Vous l'utilisez comme suit où que db est à l'origine DbContext et db.CreateInstance() crée une nouvelle instance à l'aide de la même chaîne de connexion.
C'est un peu difficile à résoudre ce un sans savoir ce que l'exception interne résultat est, le cas échéant. Cela pourrait tout simplement être un problème avec la façon dont la chaîne de connexion ou de configuration du fournisseur est mis en place.
En général, vous devez être prudent avec le code parallèle et EF. Ce que vous faites -doit - travail, cependant. Une question dans mon esprit; Est tout le travail fait sur une autre instance de ce contexte avant le parallèle? En fonction de votre poste, vous êtes en train de faire un autre contexte, dans chaque thread. Ce qui est bon. Une partie de moi des merveilles cependant si il y a un peu intéressant constructeur de contention entre les multiples contextes. Si vous n'utilisez pas que le contexte n'importe où avant que parallèle, je suggère d'essayer d'exécuter une simple requête sur le contexte de l'ouvrir et assurez-vous que tous les EF bits sont tirés avant l'exécution de la méthode en parallèle. Je vais vous avouer, je n'ai pas essayé exactement ce que vous avez ici, mais je l'ai fait fermer et cela a fonctionné.