C#中使用不安全方法的多线程

时间:2016-10-18 12:50:03

标签: c# multithreading entity-framework parallel.foreach

我有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秒才能执行每条记录,我的代码有什么问题? 我应该使用其他一些多线程技术。

1 个答案:

答案 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;
    }