Comment rendre deux requêtes SQL vraiment asynchrones
Mon problème est basée sur un projet réel problème, mais je n'ai jamais utilisé le System.Threading.Tasks
bibliothèque ou d'effectuer toute graves de programmation impliquant des threads donc ma question peut être un mélange de manque de connaissances au sujet de la bibliothèque et, plus généralement, de l'incompréhension de ce qui asynchrone signifie vraiment en termes de programmation.
Donc, mon monde réel de cas est-ce - j'ai besoin de récupérer des données sur un utilisateur. Dans mon scénario actuel c'est les données financières, donc disons que j'ai besoin de tous Accounts
tous les Deposits
et tous les Consignations
pour un utilisateur spécifique. Dans mon cas, cela signifie pour la requête millions d'enregistrements pour chaque établissement et chaque requête est relativement lente, en lui-même, cependant, pour aller chercher de l' Accounts
est plusieurs fois plus lent que l'extraction de l' Deposits
. J'ai donc défini trois classes pour les trois produits de la banque, je vais les utiliser et quand je veux extraire les données pour tous les produits de la banque de l'utilisateur-je faire quelque chose comme ceci :
List<Account> accounts = GetAccountsForClient(int clientId);
List<Deposit> deposits = GetDepositsForClient(int clientId);
List<Consignation> consignations = GetConsignationsForClient(int clientId);
De sorte que le problème commence ici j'ai besoin d'obtenir tous les trois en même temps, parce que je vais le passer à la vue où j'affiche tous les utilisateurs de données. Mais comme il est en ce moment à l'exécution synchrone (Si je suis en utilisant le terme correctement ici) donc le temps total de la collecte des données pour l'ensemble des trois produits est:
Total_Time = Time_To_Get_Accounts + Time_To_Get_Deposits + Time_To_Get_Consignations
Ce n'est pas une bonne chose, car chaque requête est relativement lente, de sorte que le temps total est assez grande, mais aussi, la accounts
requête prend beaucoup plus de temps que les deux autres requêtes, l'idée que dans ma tête aujourd'hui, c'était - "si je pouvais exécuter cette requêtes simultanément". Peut-être vient ici mon plus gros malentendu sur le sujet, mais pour moi le plus proche de cette idée est de leur faire asynchrone donc peut-être alors Total_Time
ne sera pas le moment le plus lent de la requête, mais encore sera beaucoup plus rapide que la somme de tous les trois requêtes.
Depuis que mon code est compliqué, j'ai créé un cas d'utilisation simple qui, je pense, reflète ce que je suis en train de faire assez bien. J'ai deux méthodes :
public static async Task<int> GetAccounts()
{
int total1 = 0;
using (SqlConnection connection = new SqlConnection(connString))
{
string query1 = "SELECT COUNT(*) FROM [MyDb].[dbo].[Accounts]";
SqlCommand command = new SqlCommand(query1, connection);
connection.Open();
for (int i = 0; i < 19000000; i++)
{
string s = i.ToString();
}
total1 = (int) await command.ExecuteScalarAsync();
Console.WriteLine(total1.ToString());
}
return total1;
}
et la deuxième méthode :
public static async Task<int> GetDeposits()
{
int total2 = 0;
using (SqlConnection connection = new SqlConnection(connString))
{
string query2 = "SELECT COUNT(*) FROM [MyDb].[dbo].[Deposits]";
SqlCommand command = new SqlCommand(query2, connection);
connection.Open();
total2 = (int) await command.ExecuteScalarAsync();
Console.WriteLine(total2.ToString());
}
return total2;
}
qui je l'appelle comme ceci:
static void Main(string[] args)
{
Console.WriteLine(GetAccounts().Result.ToString());
Console.WriteLine(GetDeposits().Result.ToString());
}
Comme vous pouvez le voir j'appelle GetAccounts()
premier et j'ai ralentir l'exécution vers le bas sur le but j'ai donc donner une chance de continuer l'exécution de la méthode suivante. Cependant, je ne suis pas arriver à aucun résultat pour une certaine période de temps et puis je reçois tout imprimé sur la console en même temps.
Donc le problème: comment faire en sorte que je ne pas attendre, pour la première méthode pour terminer, afin de passer à la méthode suivante. En général, la structure du code n'est pas si important que cela, ce que je veux vraiment savoir si il y a moyen de faire deux requêtes à exécuter en même temps. L'exemple ici est le résultat de ma recherche qui peut-être pourrait être étendu au point où je vais obtenir le résultat souhaité.
P. S
Je suis en utilisant ExecuteScalarAsync();
juste parce que j'ai commencé avec une méthode qui a été de l'utiliser. En réalité, je vais utiliser Scalar
et Reader
.
source d'informationauteur Leron | 2014-10-10
Vous devez vous connecter pour publier un commentaire.
Lorsque vous utilisez le
Result
de propriété sur une tâche qui n'a pas encore terminé le thread bloqué jusqu'à ce que l'opération est terminée. Cela signifie que dans votre cas, leGetAccounts
opération doit se terminer avant l'appel àGetDeposits
commence.Si vous voulez vous assurer que ces méthodes sont parallèles (y compris la machine synchrone CPU-intensive pièces), vous devez décharger de ce travail pour un autre thread. La façon la plus simple de le faire serait d'utiliser
Task.Run
:Parce que
Main
ne peut pas êtreasync
et ne peut donc pas utiliserawait
vous pouvez simplement appeler cette méthode et de façon synchrone attendre pour elle de remplir à l'aide deWait
.Ici un moyen d'effectuer deux tâches en mode asynchrone et en parallèle:
Je préfère généralement utiliser les groupes de travail.WaitAll. Pour la configuration de ce segment de code, j'ai changé le GetAccounts/GetDeposits signatures juste de retour de type int (
public static int GetAccounts()
)J'ai mis la Console.WriteLine dans le même thread que l'attribution de la retourner pour valider que l'on GetDeposits retourne avant GetAccounts a, mais c'est inutile et probablement le meilleur pour la déplacer après la
Task.WaitAll
Si c'est ASP.NET utiliser AJAX pour récupérer après que la page est affichée et de mettre les données dans un magasin. Chaque AJAX extraction est asynchrone. Si vous souhaitez créer simultanée des requêtes SQL sur le serveur?
Utilisation:
Source: