最近想調整一段迴圈的程式
想到並行這做法
剛好有幾個問題想請教一下
以下是我的程式碼
var sBachSQL = new ConcurrentBag<資料庫連接相關CLASS>();
try{
Count = 0;
SqlString = "";
string[] lines = File.ReadAllLines(Path);
if (lines != null && lines.Count() > 0)
{
Parallel.ForEach(lines, (item, loopState) =>
{
string data = item.ToString();
try
{
//解析並回傳更新的SQL語法
SqlString = RerurnSqlString(data);
}
catch (Exception exc)
{
}
if (SqlString.Trim() != "")
{
sBachSQL.Add(SqlString);
Count++;
}
//每1000筆執行一次交易
if ((Count == 1000))
{
ExecuteTransaction(SqlString);
Count = 0;
SqlString = "";
sBachSQL = new ConcurrentBag<資料庫連接相關CLASS>();
}
});
}
}
功能大概是我會讀取一個TXT檔,裡面可能會有上萬筆資料,讀取後
解析某個欄位並回傳SQL更新語法然後每1000筆進行一次交易
目前的問題是我寫LOG記錄我的COUNT數時我發現他不一定會呈現
0、1、2、3、4、5
有可能會呈現
0、1、1、2、4、5
或是別的可能性
我能請問是為什麼嗎?
這是多執行緒取值的問題,Parallel.ForEach 也是一種多執行緒,如果需要修改相同的值需要使用lock
實際上完成的需求是甚麼我不太清楚, 你可以查一下Parallel.ForEach 跟 lock 的使用
如:https://dotblogs.com.tw/JesperLai/2018/04/06/010817
我想再請問,執行完後看一下資料庫發現有的資料沒更新到有可能也是這原因嗎?
應該是相同原因, 你的 sBachSQL 這個變數也在多執行緒裡面被修改到.
另外,在執行緒中計數感覺不太保險.因為用lock雖然可以確定參數一次只有一個執行緒取得,但是無法確定取得的順序.
事先切割好陣列在進行多執行緒執行可能會比較好.
比如 1500 筆資料, 先切分 1000 + 500 在執行動作, 這樣就不用在裡面計數.
你指定Count為1000才執行交易,若你的總行數為3999
即是跑到最後一行 Count為999就結束了,那麼最後999比是否就沒有成功交易?你似乎沒有做最後未滿1千筆時的判定..
加上你用Parallel,Count沒有鎖定的狀態下,你甚至估不到最後有多少筆沒送...
這是我的猜測~
Yue感謝,這個想法我倒是沒想過,假設我有4000筆資料我有辦法分組成4個1000筆?計數那個只是我想觀察
緯大啊緯大人未滿1000筆的交易我有做,只是不是寫在Parallel裡。我這隻程式原本只是普通的迴圈,基於好奇我把它改成Parallel看看
噗 那我誤會了
沒關係,分組的我倒是做好了,沒想到還有這種做法,哈哈,我看看後面怎麼弄~
另外, 你也可以參考
https://dotblogs.com.tw/supershowwei/2016/12/09/221622
使用SqlBulkCopy 批次 Insert的方式,將工作丟給資料庫去執行分類
這樣你也不用自己分資料跟執行緒