你幾乎沒有。總結你在一個函數貼有此標誌的代碼:
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