Sie sind fast da. Wickeln Sie den Code, den Sie in einer Funktion mit dieser Signatur geschrieben:
IEnumerable<IDataRecord> MyQuery()
und dann ersetzen Sie // Do something with Reader
Code mit diesem:
yield return reader;
Jetzt haben Sie etwas haben, das in einem einzigen Thread funktioniert. Wenn Sie die Abfrageergebnisse durchlesen, wird leider jedes Mal ein Verweis auf das Objekt selbe zurückgegeben, und das Objekt mutiert sich für jede Iteration einfach selbst. Dies bedeutet, dass Sie, wenn Sie versuchen, es parallel auszuführen, einige wirklich merkwürdige Ergebnisse erhalten, da parallele Lesevorgänge das in verschiedenen Threads verwendete Objekt mutieren. Sie benötigen Code, um eine Kopie des Datensatzes an Ihre parallele Schleife zu senden.
Zu diesem Zeitpunkt, was ich tun möchte, ist jedoch überspringen die zusätzliche Kopie des Datensatzes und direkt zu einer stark typisierten Klasse. Mehr als das, Ich mag eine allgemeine Methode verwenden, es zu tun:
IEnumerable<T> GetData<T>(Func<IDataRecord, T> factory, string sql, Action<SqlParameterCollection> addParameters)
{
using (var cn = new SqlConnection("My connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
addParameters(cmd.Parameters);
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return factory(rdr);
}
}
}
}
Angenommen, Ihre Fabrik Methoden erstellen eine Kopie als erwartet, soll dieser Code sicher in einer Parallel.ForEach Schleife zu verwenden.
var UnderPaid = GetData<Employee>(Employee.Create,
"SELECT * FROM Employee WHERE AnnualSalary <= @MinSalary",
p => {
p.Add("@MinSalary", SqlDbType.Int).Value = 50000;
});
Parallel.ForEach(UnderPaid, e => e.GiveRaise());
Wichtiges Update: in diesem Code als ich
Ich bin nicht so sicher Aufruf die Methode würde in etwa so aussehen (eine ein Employee-Klasse mit einer statischen Factory-Methode namens „Create“ vorausgesetzt) war einmal.Ein separater Thread könnte den Leser immer noch mutieren, während ein anderer Thread gerade dabei ist, seine Kopie zu erstellen. Ich könnte eine Sperre um das machen, aber ich bin auch besorgt, dass ein anderer Thread den Leser aktualisieren könnte, nachdem das Original selbst Read() aufgerufen hat, aber bevor es beginnt, die Kopie zu machen. Daher besteht der kritische Abschnitt hier aus der gesamten while-Schleife ... und an diesem Punkt sind Sie wieder zurück zum single-threaded. Ich erwarte, dass es eine Möglichkeit gibt, diesen Code so zu modifizieren, dass er für Multi-Threaded-Szenarien wie erwartet funktioniert, aber es wird mehr Studien benötigen.
ich bin mit dir für die meisten von dem, was Sie gesagt haben, verloren Sie mich ein wenig an der Fabrik. Func factory stimmt nicht mit dem Aufruf überein, wenn er mit yeild return factor (rdr) verwendet wird. Ich denke, Sie haben Func gemeint. Also nicht sicher, was du mit Kopie wie erwartet meinst. Meinst du damit, dass du grundsätzlich vom Leser liest und eine MyDataClass zurückschickst, ähnlich wie Reed in seiner Antwort gesagt hat? –
Sieht auch so aus, als ob Ihr GetData-Aufruf unser Auftrag ist, dass Sie die Factory-Funktion vor der SQL-Zeichenfolge haben. Unabhängig davon, denke ich, bekomme ich es, Ihre Employee.Create ist Ihre Fabrik, die die Arbeit mit dem Leser benötigt. Ich werde eine Weile damit spielen und sehen, wie es läuft. –
Ja, ich meinte Func. Wird das beheben und der Parameter stimmt nicht überein. –