你几乎没有。总结你在一个函数贴有此标志的代码:
IEnumerable<IDataRecord> MyQuery()
,然后用这个替换您的// Do something with Reader
代码:
yield return reader;
现在你有一些在单线程工作。不幸的是,当你通过查询读取结果这是一个参考,每次回到相同对象,该对象只是变异本身对每个迭代。这意味着如果你试图并行运行它,你会得到一些非常奇怪的结果,因为平行读取会改变不同线程中使用的对象。您需要使用代码将记录的副本发送到并行循环。
在这一点上,不过,我喜欢做的是跳过记录的额外拷贝,直接进入到一个强类型的类。更重要的是,我喜欢用一个通用的方法来做到这一点:
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);
}
}
}
}
假设你的工厂方法创建如预期的副本,此代码应该是安全的Parallel.ForEach循环使用。调用该方法会是这个样子(假设一个Employee类名为静态工厂方法“创建”):
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());
重要更新:
我不是这个代码,我一样自信曾经是。当另一个线程正在进行复制时,一个单独的线程仍然可以改变读者。我可以对此加以锁定,但是我也担心另一个线程可能会在原始文件自己调用Read()之后但在开始复制之前调用更新阅读器。因此,这里的关键部分由整个while循环组成......在这一点上,你又回到了单线程。我期望有一种方法可以修改此代码,以便按照预期为多线程场景工作,但需要更多的研究。
我跟你说你说的大部分内容,你在工厂上让我失去了一点点。当使用yeild return factor(rdr)时,Func工厂不匹配调用我认为你的意思是Func 。所以不知道你的意思是按照预期复制。你的意思是基本上从读者那里读取并返回类似于里德在回复中所说的MyDataClass? –
2010-06-22 23:10:59
也看起来像你的GetData调用是我们的命令你有工厂func之前的SQL字符串。无论我认为我得到了它,您的Employee.Create是您的工厂,能够为读者提供所需的工作。我会玩一会儿,看看它是如何发生的。 – 2010-06-22 23:25:02
是的,我的意思是Func。将解决这个问题和参数不匹配。 –
2010-06-22 23:43:04