我有Datatable
有数百万条记录,我使用Parallel.Foreach
来获取每条记录。对于每条记录,调用方法AddAttendace
。
var AttCollection = from o in Employees
select o;
Parallel.ForEach(AttCollection, ac =>
{
AddAttendace(_ep.Get_V(ac.Key, true, null), ac.Value);
});
在AddAttendace
方法中,调用其他多个方法使用数据库连接从数据库中获取数据,我正在使用实体框架工作。
public bool AddAttendace(V_HR_EmployeePlacementDetailed emp, DateTime dt)
{
var empPos = _position.Get(emp.department_id, emp.position_id);
var empPosRoster = _rosterPosition.Get(emp.department_id, emp.position_id, dt);
var empPosLateArrival = empPos.late_arrival;
var empPosEarlyDeparture = empPos.early_departure;
if (empPosRoster != null)
{
empPosLateArrival = empPosRoster.late_arrival.HasValue ? empPosRoster.late_arrival.Value : empPosLateArrival;
empPosEarlyDeparture = empPosRoster.early_departure.HasValue ? empPosRoster.early_departure.Value : empPosEarlyDeparture;
}
var empLeaves = _lapp.GetAll(null, null, dt, dt, null, true, null, null, null, null);
var att = GetAll(dt, new List<long> { emp.employee_id });
var obj = att.Count() > 0 ? att.First() : Get();
var inRecords = _inOut.GetAll(obj.employee_attendance_id, true, null);
var outRecords = _inOut.GetAll(obj.employee_attendance_id, null, true);
obj.employee_id = emp.employee_id;
obj.date = dt;
obj.arrival_time = inRecords.Count() == 0 ? dt.TimeOfDay : obj.arrival_time;
obj.departure_time = inRecords.Count() > 0 ? dt.TimeOfDay : obj.departure_time;
dt.TimeOfDay - inRecords.First().@in.Value : obj.total_hours_worked;
if (obj.arrival_time.HasValue && empPosLateArrival.HasValue && obj.arrival_time > empPosLateArrival)
obj.late_arrival = obj.arrival_time - empPosLateArrival;
if (obj.early_departure.HasValue && empPosEarlyDeparture.HasValue && obj.departure_time < empPosEarlyDeparture)
obj.early_departure = empPosEarlyDeparture - obj.departure_time;
obj.present = true;
obj.leave = false;
obj.holiday = false;
obj.department_id = emp.department_id;
obj.position_id = emp.position_id;
var lapp = (from o in empLeaves
where o.employee_id == emp.employee_id
select o).FirstOrDefault();
if (lapp != null && obj.present != true){
obj.leave = true;
obj.leave_type_id = lapp.LeaveTypeId;
}
var v = _inOut.Get();
if (att.Count() > 0){
Update();
v.attendance_id = obj.employee_attendance_id;
}
else{
Insert(obj);
v.attendance_id = GetCurrentIdent();
}
if (inRecords.Count() == 0){
v.@in = dt.TimeOfDay;
v.inout_type_id = 1;
}
else{
v.@out = dt.TimeOfDay;
v.inout_type_id = 2;
}
_inOut.Insert(v);
return false;
}
AddAttendace
需要2秒才能完成执行,而12000
记录需要很长时间才能执行,所以这就是我使用Parallel.Foreach的原因。但是AddAttendace
内部调用的其他多个方法都是线程不安全的,我在每个方法中都使用lock
语句
public V_HR_EmployeePlacementDetailed Get_V(long employeeID, bool? IsActivePlacement, bool? IsActive)
{
lock (locker)
{
var result = from o in entity.V_HR_EmployeePlacementDetailed
where o.employee_id == employeeID
&& ((IsActive.HasValue && o.IsActive == IsActive)
|| !IsActive.HasValue)
&& ((IsActivePlacement.HasValue && o.IsActiveInPlacement == IsActivePlacement)
|| !IsActivePlacement.HasValue)
orderby o.employee_placement_id descending
select o;
return result.FirstOrDefault();
}
}
但是AddAttendace
方法仍需要2秒才能执行每条记录,我的代码有什么问题?
我应该使用其他一些多线程技术。
答案 0 :(得分:2)
您真的需要对此进行分析以获取更多信息。盲目地解决问题可能只会导致更多的麻烦。 Visual Studio包含最新版本的探查器,或者您可以使用Redgate的ANTS等工具。如果你无法解决这个问题,你可以简单地在整个代码中记录时间记录,以缩小问题范围(见下文)。只有当你知道导致问题的确切线路时才值得优化。
public bool AddAttendace(V_HR_EmployeePlacementDetailed emp, DateTime dt)
{
var stopWatch = System.Diagnostics.Stopwatch.StartNew();
var empPos = _position.Get(emp.department_id, emp.position_id);
System.Diagnostics.Debug.WriteLine("a {0}", stopWatch.ElapsedTicks);
var empPosRoster = _rosterPosition.Get(emp.department_id, emp.position_id, dt);
System.Diagnostics.Debug.WriteLine("b {0}", stopWatch.ElapsedTicks);
var empPosLateArrival = empPos.late_arrival;
var empPosEarlyDeparture = empPos.early_departure;
System.Diagnostics.Debug.WriteLine("c {0}", stopWatch.ElapsedTicks);
if (empPosRoster != null)
{
empPosLateArrival = empPosRoster.late_arrival.HasValue ? empPosRoster.late_arrival.Value : empPosLateArrival;
empPosEarlyDeparture = empPosRoster.early_departure.HasValue ? empPosRoster.early_departure.Value : empPosEarlyDeparture;
System.Diagnostics.Debug.WriteLine("d {0}", stopWatch.ElapsedTicks);
}
var empLeaves = _lapp.GetAll(null, null, dt, dt, null, true, null, null, null, null);
System.Diagnostics.Debug.WriteLine("e {0}", stopWatch.ElapsedTicks);
var att = GetAll(dt, new List<long> { emp.employee_id });
System.Diagnostics.Debug.WriteLine("f {0}", stopWatch.ElapsedTicks);
var obj = att.Count() > 0 ? att.First() : Get();
System.Diagnostics.Debug.WriteLine("g {0}", stopWatch.ElapsedTicks);
var inRecords = _inOut.GetAll(obj.employee_attendance_id, true, null);
System.Diagnostics.Debug.WriteLine("h {0}", stopWatch.ElapsedTicks);
var outRecords = _inOut.GetAll(obj.employee_attendance_id, null, true);
System.Diagnostics.Debug.WriteLine("i {0}", stopWatch.ElapsedTicks);
obj.employee_id = emp.employee_id;
obj.date = dt;
obj.arrival_time = inRecords.Count() == 0 ? dt.TimeOfDay : obj.arrival_time;
obj.departure_time = inRecords.Count() > 0 ? dt.TimeOfDay : obj.departure_time;
System.Diagnostics.Debug.WriteLine("j {0}", stopWatch.ElapsedTicks);
dt.TimeOfDay - inRecords.First().@in.Value : obj.total_hours_worked;
System.Diagnostics.Debug.WriteLine("k {0}", stopWatch.ElapsedTicks);
if (obj.arrival_time.HasValue && empPosLateArrival.HasValue && obj.arrival_time > empPosLateArrival)
{
obj.late_arrival = obj.arrival_time - empPosLateArrival;
System.Diagnostics.Debug.WriteLine("l {0}", stopWatch.ElapsedTicks);
}
if (obj.early_departure.HasValue && empPosEarlyDeparture.HasValue && obj.departure_time < empPosEarlyDeparture)
{
obj.early_departure = empPosEarlyDeparture - obj.departure_time;
System.Diagnostics.Debug.WriteLine("m {0}", stopWatch.ElapsedTicks);
}
obj.present = true;
obj.leave = false;
obj.holiday = false;
obj.department_id = emp.department_id;
obj.position_id = emp.position_id;
System.Diagnostics.Debug.WriteLine("n {0}", stopWatch.ElapsedTicks);
var lapp = (
from o in empLeaves
where o.employee_id == emp.employee_id
select o).FirstOrDefault();
System.Diagnostics.Debug.WriteLine("o {0}", stopWatch.ElapsedTicks);
if (lapp != null && obj.present != true)
{
obj.leave = true;
obj.leave_type_id = lapp.LeaveTypeId;
System.Diagnostics.Debug.WriteLine("p {0}", stopWatch.ElapsedTicks);
}
var v = _inOut.Get();
System.Diagnostics.Debug.WriteLine("q {0}", stopWatch.ElapsedTicks);
if (att.Count() > 0)
{
Update();
v.attendance_id = obj.employee_attendance_id;
System.Diagnostics.Debug.WriteLine("r {0}", stopWatch.ElapsedTicks);
}
else
{
Insert(obj);
v.attendance_id = GetCurrentIdent();
System.Diagnostics.Debug.WriteLine("s {0}", stopWatch.ElapsedTicks);
}
if (inRecords.Count() == 0)
{
v.@in = dt.TimeOfDay;
v.inout_type_id = 1;
System.Diagnostics.Debug.WriteLine("t {0}", stopWatch.ElapsedTicks);
}
else
{
v.@out = dt.TimeOfDay;
v.inout_type_id = 2;
System.Diagnostics.Debug.WriteLine("u {0}", stopWatch.ElapsedTicks);
}
_inOut.Insert(v);
System.Diagnostics.Debug.WriteLine("v {0}", stopWatch.ElapsedTicks);
return false;
}