À l'aide de async / await avec DataReader ? ( sans moyen de tampons!)
Mon but est simple , je veux faire des e/S Asynchrones appels (à l'aide de async attendent) - mais :
- Sans l'aide de Flux de données de la dépendance ( comme dans cette réponse,)
- Sans moyen de tampons( ce n'est pas comme cette réponse)
- La fonction de Projecteur doit être envoyé comme un argument. ( ce n'est pas comme cette réponse)
Ok.
Actuellement voici mon code c'est du boulot, c'est de lire à partir de db et le projet de chaque ligne à un Func<>
public IEnumerable < T > GetSomeData < T > (string sql, Func < IDataRecord, T > projector)
{
using(SqlConnection _conn = new SqlConnection(@"Data Source=..."))
{
using(SqlCommand _cmd = new SqlCommand(sql, _conn))
{
_conn.Open();
_cmd.CommandTimeout = 100000;
using(IDataReader rdr = _cmd.ExecuteReader())
{
while (rdr.Read()) yield return projector(rdr);
}
}
}
}
Alors , qu'est-projecteur ?
Chaque classe a une fonction qui reçoit un record
( IDataRecord
) et de créer une entité :
Exemple :
public class MyClass
{
public static MyClass MyClassFactory(IDataRecord record)
{
return new MyClass
{
Name = record["Name"].ToString(),
Datee = DateTime.Parse(record["Datee"].ToString()),
val = decimal.Parse(record["val"].ToString())
};
}
public string Name { get; set; }
public DateTime Datee { get; set; }
public decimal val { get; set; }
}
Donc, ici , MyClassFactory
serait le Func
Alors, comment je fonctionne actuellement ?
var sql = @"SELECT TOP 1000 [NAME],[datee] ,[val] FROM [WebERP].[dbo].[t]";
var a = GetSomeData < MyClass > (sql, MyClass.MyClassFactory).Where(...); //notice the Func
Tous ok.
Le problème commence maintenant :
Ajoutant async
à la méthode donne une erreur : ( Oui, je sais que Ienumerable est un Synchrone interface d'où le problème)
public async Task<IEnumerable < T >> GetSomeData < T > (string sql, Func < IDataRecord, T > projector)
ne peut pas être un itérateur bloc parce que
'Système.Le filetage.Les tâches.Tâche>'
n'est pas un itérateur type d'interface
Qui NE compiler.
Question
Comment puis-je convertir mon code à soutenir pleinement asynchronse IO appel ?
(selon les conditions : sans des Flux de données, de dépendance , d'envoyer le projecteur en fonction comme argument , aucun moyen de tampons)
IAsyncEnumerator
. Si vous êtes OK avec le retour d'un rendez-vous rempli de liste dans un async façon dont la question devient beaucoup plus facile.ToArray
permet de créer un milieu tampon.Votre code d'itérations. Le code qui ne compile pas. IEnumerable n'est pas le problème. L'itération (c'est à dire:
yield return
) est le problème. Quel est le problème avec un tampon?Que diriez - asyncenum.codeplex.com
vous avez de l'exposer à l'appelant par l'élément de l'asynchronicité. IEnumerable ne peut pas le faire. En prenant un élément est toujours synchrone. Vous avez besoin d'utiliser un modèle asynchrone comme IAsyncEnumerator. Il semble raisonnable de bibliothèques autour de cette idée (asyncenum.codeplex.com). Rien de construit. Aussi, l'impact sur les performances prises pour la mise en mémoire tampon est si peu par rapport à tous les ADO.NET et SQL travail en évitant de mise en mémoire tampon ne pas avoir un effet significatif du débit. Aurait encore un sens pour la diffusion d'énormes ensembles de données.
OriginalL'auteur Royi Namir | 2014-05-25
Vous devez vous connecter pour publier un commentaire.
Vous voudrez peut-être vérifier Stephen Toub du "Les tâches, les Monades, et LINQ" pour quelques bonnes idées sur la façon de processus asynchrone de données de séquences.
Il n'est pas (encore) possible de combiner
yield
etawait
, mais je vais être un verbalist ici: la cité des exigences n'a pas de listeIEnumerable
et LINQ. Alors, voici une solution possible à la forme de deux coroutines (presque non testé).Producteur des données de routine (correspond à
IEnumarable
avecyield
):Consommateur de données de routine (correspondent à
foreach
ou une expression LINQ):Coroutine exécution helper (peut également être mis en œuvre comme une paire de personnalisé awaiters):
C'est juste une idée. Il serait peut-être trop pour une tâche simple comme ça, et elle pourrait être améliorée dans certains domaines (comme le fil de sécurité, des conditions de course et de la manipulation de la fin de la séquence, sans toucher
producerTask
). Pourtant, il montre comment la asynchrones extraction de données et de traitement pourrait éventuellement être découplés.GetSomeDataAsync
est utilisé avecConsumeSomeDataAsync
. À la fois prendre la commande sql ??appels
GetSomeDataAsync
pour démarrer la séquence et simplement il passe lesql
chaîne.Pourrais-je être en mesure de faire quelque chose comme
ConsumeSomeDataAsync().Where(...)
? ( actuellement non)voici un simple violon montrant le concept: dotnetfiddle.net/8gQVt2. Non, vous ne serez pas en mesure d'utiliser la norme de LINQ.
Je suppose que vous pourriez dire. Au sens figuré, c'est un cas particulier de producteur/consommateur, motif, avec la taille de file d'attente de 1 élément et sans blocage de tous les threads. TPL Dataflow permet beaucoup plus de scénarios complexes. Ensuite, il y a aussi des Rx.
OriginalL'auteur noseratio