【答客問】耗時Stored Procedure的ASP.NET Postback進度回報寫法
0 |
【問題】
在耗時ASP.NET Postback的傻瓜進度回報一文,雖然示範了跑迴圈定期呼叫ReportProgress委派傳回進度的貼心做法,實務上卻難以實現,例如: 某個Stored Procedure要跑一分鐘,在IDbCommand.ExecuteNonQuery()執行結束前,根本什麼都不能做,又如何能定期丟進度給前端?
les.Execute(
sender as Button,
(rp) =>
{
//模擬執行很耗時的作業
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1000);
//處理到一個段落,呼叫Delegate傳回訊息
rp("Process - " + i.ToString());
}
});
【建議】
想在執行耗時動作時繼續擁有控制權,最簡單的做法是另開一條執行緒專門陪它玩,呼叫端可透過迴圈方式等待結果,在等待期間還能進行其他動作。不過除非有特殊設計,呼叫Stored Proceudre期間我們無從掌握進度也無法預測完成時間,能做的只有累計執行時間持續回報,讓使用者確認程式仍在執行中稍安勿躁。依據經驗,只要能提供線索(哪怕只是無意義的讀秒)讓使用者確認程式沒當掉,在使用體驗上便已遠勝"按鈕之後音訊全無"。
程式範例如下,原理是先宣告一個done旗標,然後開一條Thread專門執行耗時作業,結束時將done設為true;原來的Thread則跑while迴圈等待done變成true,等待期間重複Thread.Sleep 1秒後送一次執行秒數的動作,周而復始,如此就能達成呼叫Stored Procedure時持續傳回報的效果囉~
protected void btnLongExec_Click(object sender, EventArgs e)
{
les.Execute(
sender as Button,
(rp) =>
{
bool done = false;
int i = 0;
//另開一條Thread執行耗時作業,完成時將done設為true
Thread t = new Thread(() =>
{
//執行同步式耗時作業,例如執行Stored Procedure、大規模DB批次更新
//在此使用Thread.Sleep取代之
Thread.Sleep(20000);
done = true;
});
t.Start();
//跑迴圈等候,每隔一秒傳回耗時統計(如有需要還可加入Timeout概念)
while (!done)
{
Thread.Sleep(1000);
i++;
rp("Process - " + i.ToString());
}
});
}
PS: 如果平台為.NET 4.5,非同步作業亦可用async/await實現,更為方便。
Comments
Be the first to post a comment