Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to work with Task Parallel library with DataReader

i often populate data reader with data and populate UI like this way

using (SqlConnection conn = new SqlConnection("myConnString"))
using (SqlCommand comm = new SqlCommand("Select * from employee where salary<5000", conn))
{
    conn.Open();

    SqlDataReader reader = comm.ExecuteReader();

    if (reader.HasRows)
    {
        while (reader.Read())
        {
            // here i populate my employee class
        }
    }
    // here i update UI
}

i was searching for the use of Task Parallel library with DataReader and found piece of code. it looks nice but objective is not very clear to me. so here is the code i got.

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 ...);
        }
    }
}
}

calling like

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

OR

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

how could i get the data from ForAll.

can anyone help me to understand the code snippet that how it works and how to get data from ForAll and how can i populate my UI from ForAll.

another question that how do i know that which class is thread safe or not. what does it mean thread safe. a person said datareader is not thread safe. how he knows.

another question when one should use task parallel library. please guide. thanks

like image 938
Thomas Avatar asked Aug 14 '12 09:08

Thomas


1 Answers

You can find information about thread-safety of every type in the .NET base class library in the MSDN documentation. Most types are not thread-safe. SqlDataReader for instance, is not thread-safe, since it works on a single connection to the database.

However, Parallel.ForEach is a very clearer construct. You can't really iterate an IEnumerable with multiple thread simultaneously, and Parallel.ForEach doesn't do that. Although it spins up multiple threads and those multiple threads do iterate on the given IEnumerable, Parallel.ForEach ensures that only one thread at the time iterates the enumerable's IEnumerator. It operates on the assumption that processing elements takes more time than getting the items from the enumerable. Iterating the enumerable is a sequential operation.

This means that even if the underlying data source and the use of the SqlReader is not thread-safe, you can still process the items in parallel using the Parallel.ForEach. Unfortunately, the MSDN documentation isn't very explicit about this, but it has to be, since IEnumerator instances returned from GetEnumerator() methods are never thread-safe.

Still you have to make sure that the given Action<T> is thread-safe, of course.

You can see this behavior, using the following program:

public static IEnumerable<int> GetNumbers()
{
    for (int i = 0; i < 140; i++)
    {
        Console.WriteLine(
            "                          Enumerating " + 
            i + " at thread " +
            Thread.CurrentThread.ManagedThreadId);

        yield return i;
    }
}

static void Main(string[] args)
{
    Console.ReadLine();

    Parallel.ForEach(GetNumbers(), number =>
    {
        Console.WriteLine("Processing " + number + 
            " at thread " +
            Thread.CurrentThread.ManagedThreadId);

        Thread.Sleep(1);
    });
}
like image 78
Steven Avatar answered Nov 06 '22 15:11

Steven