[C#] Есть ли способ использовать параллельную библиотеку задач (TPL) с SQLDataReader?


Answers

У вас будет трудность заменить это на цикл. SqlDataReader не является потокобезопасным классом, поэтому вы не можете использовать его напрямую из нескольких потоков.

При этом вы можете обрабатывать данные, которые вы читаете, используя TPL. Здесь есть несколько вариантов. Самый простой способ - сделать свою собственную реализацию IEnumerable<T> которая работает с читателем, и возвращает класс или структуру, содержащие ваши данные. Затем вы можете использовать PLINQ или инструкцию Parallel.ForEach для Parallel.ForEach обработки ваших данных:

public IEnumerable<MyDataClass> ReadData()
{
    using (SqlConnection conn = new SqlConnection("myConnString"))
    using (SqlCommand comm = new SqlCommand("myQuery", conn))
    {
        conn.Open();

        SqlDataReader reader = comm.ExecuteReader();

        if (reader.HasRows)
        {
            while (reader.Read())
            {
                yield return new MyDataClass(... data from reader ...);
            }
        }
    }
}

После того, как у вас есть этот метод, вы можете обработать его напрямую, используя PLINQ или TPL:

Parallel.ForEach(this.ReadData(), data =>
{
    // Use the data here...
});

Или:

this.ReadData().AsParallel().ForAll(data => 
{
    // Use the data here...
});
Question

Мне нравится простота методов расширения Parallel.For и Parallel.ForEach в TPL. Мне было интересно, есть ли способ воспользоваться чем-то подобным или даже с немного более продвинутыми задачами.

Ниже приведено типичное использование для SqlDataReader, и мне было интересно, возможно ли это, и если да, то как заменить цикл while на что-то в TPL. Поскольку читатель не может предоставить фиксированное количество итераций, метод «Расширение» невозможен, что позволяет справиться с задачами, которые я собирал. Я надеялся, что кто-то, возможно, уже справился с этим, и разработал кое-что, и не наденет его на ADO.net.

using (SqlConnection conn = new SqlConnection("myConnString"))
using (SqlCommand comm = new SqlCommand("myQuery", conn))
{
    conn.Open();

    SqlDataReader reader = comm.ExecuteReader();

    if (reader.HasRows)
    {
        while (reader.Read())
        {
            // Do something with Reader
        }
    }
}