[C#]善用 TPL 非同步設計
.net4.0 後新推出TPL非同步利器,實務上只要專案使用.net4.0以上,
我都會使用TPL撰寫非同步,如遇舊專案使用ThreadPool或是IAsyncResult Interface,
大致上我也會一併改寫為TPL,至於為什麼要用TPL開發呢?
主要就是提高效能,現實世界中,
ViewModel不太可能單純只有單一資料來源或資料查詢單一作業,
可能還有下拉選單資料、其他系統介接資料、systemlog作業...等相關操作和其他資料,
這篇我簡單使用asp.net mvc with TPL測試一下同步和非同步兩者效能差異。
View
@model KOTSMS.Models.IndexBViewModel
@{
ViewBag.Title = "TPL非同步測試";
}
<h2>TPL非同步測試</h2>
@if(Model!=null)
{
<p>
<span>公司:</span>@Html.DropDownListFor(m => m.companys, Model.companys);
<span>職稱:</span>@Html.DropDownListFor(m => m.titles, Model.titles);
<span>班別:</span>@Html.DropDownListFor(m => m.branchs, Model.branchs);
<span>部門:</span>@Html.DropDownListFor(m => m.departs, Model.departs);
</p>
<span>平均花費時間(ms):@Html.Raw(Model.Avgtime)</span>
<table>
<thead>
<tr>
<th>C1</th>
<th>C2</th>
<th>C3</th>
<th>C4</th>
<th>C5</th>
<th>C6</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.kpis)
{
<tr>
<td>@Html.Raw(item.KPI_FNAME)</td>
<td>@Html.Raw(item.KPI_M_name)</td>
<td>@Html.Raw(item.KPI_D_name)</td>
<td>@Html.Raw(item.KPI_D_weight)</td>
<td>@Html.Raw(item.KPI_SUBD_Name)</td>
<td>@Html.Raw(item.KPI_SUBDESC_Name)</td>
</tr>
}
</tbody>
</table>
}
Controller
public ActionResult IndexB(string optype)
{
IndexBViewModel _IndexBViewModel = new IndexBViewModel();
int totalavg = 0;
if (optype == "async")
{
for (int i = 0; i < 5; i++)
{
Async(_IndexBViewModel);
totalavg += int.Parse(_IndexBViewModel.costtime);
}
ViewData.Model = _IndexBViewModel;
}
else
{
for (int i = 0; i < 5; i++)
{
Sync(_IndexBViewModel);
totalavg += int.Parse(_IndexBViewModel.costtime);
}
ViewData.Model = _IndexBViewModel;
}
_IndexBViewModel.Avgtime = (totalavg / 5).ToString();
return View();
}
private IndexBViewModel Sync(IndexBViewModel srcvmode)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Reset();
sw.Start();
string sqlstatement = @"select * from COMPANY";
using (SqlConnection conn = new SqlConnection(conns))
{
List<SelectListItem> ddls = new List<SelectListItem>();
using (SqlCommand cmd = new SqlCommand(sqlstatement, conn))
{
if (conn.State == System.Data.ConnectionState.Closed)
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
ddls.Add(new SelectListItem
{
Text = dr["name"].ToString(),
Value = dr["id"].ToString()
});
}
srcvmode.companys = ddls.AsEnumerable();
}
}
}
}
sqlstatement = @"select * from TITLE";
using (SqlConnection conn = new SqlConnection(conns))
{
List<SelectListItem> ddls = new List<SelectListItem>();
using (SqlCommand cmd = new SqlCommand(sqlstatement, conn))
{
if (conn.State == System.Data.ConnectionState.Closed)
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
ddls.Add(new SelectListItem
{
Text = dr["name"].ToString(),
Value = dr["id"].ToString()
});
}
srcvmode.titles = ddls.AsEnumerable();
}
}
}
}
sqlstatement = @"select * from BRANCH";
using (SqlConnection conn = new SqlConnection(conns))
{
List<SelectListItem> ddls = new List<SelectListItem>();
using (SqlCommand cmd = new SqlCommand(sqlstatement, conn))
{
if (conn.State == System.Data.ConnectionState.Closed)
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
ddls.Add(new SelectListItem
{
Text = dr["name"].ToString(),
Value = dr["id"].ToString()
});
}
srcvmode.branchs = ddls.AsEnumerable();
}
}
}
}
sqlstatement = @"select * from DEPARTMENT";
using (SqlConnection conn = new SqlConnection(conns))
{
List<SelectListItem> ddls = new List<SelectListItem>();
using (SqlCommand cmd = new SqlCommand(sqlstatement, conn))
{
if (conn.State == System.Data.ConnectionState.Closed)
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
ddls.Add(new SelectListItem
{
Text = dr["name"].ToString(),
Value = dr["id"].ToString()
});
}
srcvmode.departs = ddls.AsEnumerable();
}
}
}
}
sqlstatement = @"USP_GetGetKPIFormData";
List<KPIViewModel> kpis = new List<KPIViewModel>();
using (SqlConnection conn = new SqlConnection(conns))
{
List<SelectListItem> ddls = new List<SelectListItem>();
using (SqlCommand cmd = new SqlCommand(sqlstatement, conn))
{
if (conn.State == System.Data.ConnectionState.Closed)
conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@START_DATE", "2013-09-30");
cmd.Parameters.Add("@EMPID", "A1083");
cmd.Parameters.Add("@type", "N");
cmd.Parameters.Add("@END_DATE", "2013-10-30");
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
KPIViewModel _KPIViewModel = new KPIViewModel
{
KPI_FCODE = dr["KPI_FCODE"].ToString(),
KPI_FNAME = dr["KPI_FNAME"].ToString(),
KPI_M_code = dr["KPI_M_code"].ToString(),
KPI_M_name = dr["KPI_M_name"].ToString(),
KPI_M_weight = dr["KPI_M_weight"].ToString(),
KPI_D_code = dr["KPI_D_code"].ToString(),
KPI_D_name = dr["KPI_D_name"].ToString(),
KPI_D_weight = dr["KPI_D_weight"].ToString(),
KPI_SUBD_Name = dr["KPI_SUBD_Name"].ToString(),
KPI_SUBDESC_Name = dr["KPI_SUBDESC_Name"].ToString(),
POINT_EMP = dr["POINT_EMP"].ToString(),
KPI_DESC = dr["KPI_DESC"].ToString(),
POINT_LEADER2 = dr["POINT_LEADER2"].ToString(),
POINT_LEADER3 = dr["POINT_LEADER3"].ToString(),
PointASerial = int.Parse(dr["PointASerial"].ToString()),
PointBSerial = int.Parse(dr["PointBSerial"].ToString()),
PointCSerial = int.Parse(dr["PointCSerial"].ToString())
};
kpis.Add(_KPIViewModel);
}
srcvmode.kpis = kpis.AsEnumerable();
}
}
}
}
sw.Stop();
srcvmode.costtime = sw.ElapsedMilliseconds.ToString();
return srcvmode;
}
private IndexBViewModel Async(IndexBViewModel srcvmode)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Reset();
sw.Start();
var t0 = Task.Factory.StartNew(() =>
{
List<SelectListItem> ddls = new List<SelectListItem>();
string sqlstatement = @"select * from COMPANY";
using (SqlConnection conn = new SqlConnection(conns))
{
using (SqlCommand cmd = new SqlCommand(sqlstatement, conn))
{
if (conn.State == System.Data.ConnectionState.Closed)
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
ddls.Add(new SelectListItem
{
Text = dr["name"].ToString(),
Value = dr["id"].ToString()
});
}
srcvmode.companys = ddls.AsEnumerable();
}
}
}
}
});
var t1 = Task.Factory.StartNew(() =>
{
List<SelectListItem> ddls = new List<SelectListItem>();
string sqlstatement = @"select * from TITLE";
using (SqlConnection conn = new SqlConnection(conns))
{
using (SqlCommand cmd = new SqlCommand(sqlstatement, conn))
{
if (conn.State == System.Data.ConnectionState.Closed)
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
ddls.Add(new SelectListItem
{
Text = dr["name"].ToString(),
Value = dr["id"].ToString()
});
}
srcvmode.titles = ddls.AsEnumerable();
}
}
}
}
});
var t2 = Task.Factory.StartNew(() =>
{
List<SelectListItem> ddls = new List<SelectListItem>();
string sqlstatement = @"select * from BRANCH";
using (SqlConnection conn = new SqlConnection(conns))
{
using (SqlCommand cmd = new SqlCommand(sqlstatement, conn))
{
if (conn.State == System.Data.ConnectionState.Closed)
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
ddls.Add(new SelectListItem
{
Text = dr["name"].ToString(),
Value = dr["id"].ToString()
});
}
srcvmode.branchs = ddls.AsEnumerable();
}
}
}
}
});
var t3 = Task.Factory.StartNew(() =>
{
List<SelectListItem> ddls = new List<SelectListItem>();
string sqlstatement = @"select * from DEPARTMENT";
using (SqlConnection conn = new SqlConnection(conns))
{
using (SqlCommand cmd = new SqlCommand(sqlstatement, conn))
{
if (conn.State == System.Data.ConnectionState.Closed)
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
ddls.Add(new SelectListItem
{
Text = dr["name"].ToString(),
Value = dr["id"].ToString()
});
}
srcvmode.departs = ddls.AsEnumerable();
}
}
}
}
});
var t4 = Task.Factory.StartNew(() =>
{
string sqlstatement = @"USP_GetGetKPIFormData";
List<KPIViewModel> kpis = new List<KPIViewModel>();
using (SqlConnection conn = new SqlConnection(conns))
{
List<SelectListItem> ddls = new List<SelectListItem>();
using (SqlCommand cmd = new SqlCommand(sqlstatement, conn))
{
if (conn.State == System.Data.ConnectionState.Closed)
conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@START_DATE", "2013-09-30");
cmd.Parameters.Add("@EMPID", "A1083");
cmd.Parameters.Add("@type", "N");
cmd.Parameters.Add("@END_DATE", "2013-10-30");
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
KPIViewModel _KPIViewModel = new KPIViewModel
{
KPI_FCODE = dr["KPI_FCODE"].ToString(),
KPI_FNAME = dr["KPI_FNAME"].ToString(),
KPI_M_code = dr["KPI_M_code"].ToString(),
KPI_M_name = dr["KPI_M_name"].ToString(),
KPI_M_weight = dr["KPI_M_weight"].ToString(),
KPI_D_code = dr["KPI_D_code"].ToString(),
KPI_D_name = dr["KPI_D_name"].ToString(),
KPI_D_weight = dr["KPI_D_weight"].ToString(),
KPI_SUBD_Name = dr["KPI_SUBD_Name"].ToString(),
KPI_SUBDESC_Name = dr["KPI_SUBDESC_Name"].ToString(),
POINT_EMP = dr["POINT_EMP"].ToString(),
KPI_DESC = dr["KPI_DESC"].ToString(),
POINT_LEADER2 = dr["POINT_LEADER2"].ToString(),
POINT_LEADER3 = dr["POINT_LEADER3"].ToString(),
PointASerial = int.Parse(dr["PointASerial"].ToString()),
PointBSerial = int.Parse(dr["PointBSerial"].ToString()),
PointCSerial = int.Parse(dr["PointCSerial"].ToString())
};
kpis.Add(_KPIViewModel);
}
srcvmode.kpis = kpis.AsEnumerable();
}
}
}
}
});
Task.WaitAll(new[] { t0, t1, t2, t3,t4 });
sw.Stop();
srcvmode.costtime = sw.ElapsedMilliseconds.ToString();
return srcvmode;
}
非同步執行5次平均花費時間(ms):24
同步執行5次平均花費時間(ms):37