6

我经常用数据填充数据阅读器并像这样填充 UI

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
}

我正在使用 DataReader 搜索 Task Parallel 库的使用,并找到了一段代码。它看起来不错,但目标对我来说不是很清楚。所以这是我得到的代码。

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

打电话

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

或者

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

我如何从ForAll获取数据。

谁能帮我理解它的工作原理以及如何从ForAll获取数据以及如何从ForAll填充我的 UI的代码片段。

另一个问题是我怎么知道哪个类是线程安全的。这是什么意思线程安全。有人说数据读取器不是线程安全的。他怎么知道。

何时应该使用任务并行库的另一个问题。请指导。谢谢

4

1 回答 1

19

您可以在 MSDN 文档的 .NET 基类库中找到有关每种类型的线程安全的信息。大多数类型不是线程安全的。SqlDataReader例如,它不是线程安全的,因为它适用于与数据库的单个连接。

但是,Parallel.ForEach是一个非常清晰的构造。你不能真正地IEnumerable同时迭代一个多线程,并且Parallel.ForEach不这样做。IEnumerable尽管它启动了多个线程,并且Parallel.ForEach这些多个线程确实在给定的IEnumerator. 它假设处理元素比从可枚举中获取项目花费更多时间。迭代可枚举是一个顺序操作。

这意味着即使底层数据源和使用SqlReader不是线程安全的,您仍然可以使用Parallel.ForEach. 不幸的是,MSDN 文档对此并不是很明确,但必须如此,因为IEnumeratorGetEnumerator()方法返回的实例永远不是线程安全的。

当然,您仍然必须确保给定Action<T>的是线程安全的。

您可以使用以下程序查看此行为:

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);
    });
}
于 2012-08-14T09:52:10.873 回答