2014-04-13 5 views
0

웹 응용 프로그램은 8 개의 vCPU가있는 가상 시스템에서 호스팅됩니다. 우리는 어떻게 든 병렬 처리하고 싶은 야간 스케줄 (콘솔 app/windows 태스크 스케줄러)에서 실행되는 집중적 인 데이터 작업을 가지고 있습니다. 연산은 다양한 통계를 계산하기 위해 여러 데이터 세트에서 여러 번 반복됩니다. 현재 실행 중일 때 작업 관리자는 CPU 사용량이 13 %를 넘지 않는다고 표시합니다. 여기가상 시스템에서 AsParallel() 및/또는 Parallel.ForEach 사용

가 호출되는 방법 중 하나에서 코드 (웹 응용 프로그램은 큰 질문이다) :

Dictionary<string, List<decimal>> decimalStats = new Dictionary<string, List<decimal>>(); 

using (var db = new PDBContext()) 
{ 
    IEnumerable<FinancialYear> financialYears = db.FinancialYears; 
    IEnumerable<Section> sections; 
    IEnumerable<Question> questions; 

    IQueryable<int> orgIds = db.Organisations.Where(l => l.Sector.IndustryID == 1).Select(m => m.OrganisationID); 
    IQueryable<int> subSectionIds; 

    foreach (var financialYear in financialYears) 
    { 
     sections = db.Sections.Where(l => orgIds.Contains(l.OrganisationID) && l.FinancialYearID == financialYear.FinancialYearID && l.IsVerified.Value); 

     foreach (var section in sections) 
     { 
      subSectionIds = db.SubSections.Where(l => l.SectionID == section.SectionID).Select(m => m.SubSectionID);     
      questions = db.Questions.Where(l => subSectionIds.Contains(l.SubSectionID.Value)); 

      foreach (var question in questions) 
      { 
       var answer = db.Answers.Where(l => l.QuestionID == question.QuestionID && l.OrganisationID == section.OrganisationID && l.FinancialYearID == financialYear.FinancialYearID).FirstOrDefault(); 

       if (answer != null) 
       { 
        string key = question.QuestionID + "#" + financialYear.FinancialYearID; 

        decimal val; 
        if (decimal.TryParse(answer.Text, out val)) 
        { 
         if (decimalStats.ContainsKey(key)) 
         { 
          ((List<decimal>)decimalStats[key]).Add(val); 
         } 
         else 
         { 
          List<decimal> vals = new List<decimal>(); 
          vals.Add(val); 
          decimalStats.Add(key, vals); 
         } 
        } 
       } 
      } 
     } 
    } 

    foreach (KeyValuePair<string, List<decimal>> entry in decimalStats) 
    { 
     List<decimal> vals = ((List<decimal>)entry.Value).OrderBy(l => l).ToList(); 

     if (vals.Count > 0) 
     { 
      // lots of stuff to calculate various statistics about the data 
     } 
    } 
} 

나는 많은 위의 코드를 단순화했다. 나는 그것이 어떤 병렬 실행을 사용할 수있는 영역을 격리 시키길 바란다.

IEnumerable<FinancialYear> financialYears = db.FinancialYears.AsParallel();

Parallel.ForEach(financialYears, financialYear => { });

sections = db.Sections.Where(l => orgIds.Contains(l.OrganisationID) && l.FinancialYearID == financialYear.FinancialYearID && l.IsVerified.Value).AsParallel();

을 ...하지만 내가 아무것도 꽤 많은 숙박 요금에 13 %와 방법을 실행하는 데 걸리는 시간보다 CPU 사용량을 밀어 없습니다 :

내가 사용하는 다른 조합을 시도했습니다 똑같다. 무슨 트릭이 내가 여기에없는거야? 병렬 프로그래밍은 새로운 것이므로 가능한 한 PLINQ/TPL을 사용하려고합니다.

+0

[DbContext] (http://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext (v = vs.113) .aspx # Thread % 20Safety)는 스레드로부터 안전하지 않으므로 사용할 작업/스레드마다 별도로 하나 만들어야합니다. 기껏해야, 잠금으로 인해 속도가 느려질 수 있습니다. 최악의 경우에는 매번 작동하지 않습니다. –

답변

1

문제는 CPU에서보다 데이터베이스 쿼리에있을 가능성이 큽니다.

CPU 작업을 병렬화하는 대신 쿼리 수를 최소화하고 해당 쿼리에서 오는 데이터의 수를 최대화하는 것이 좋습니다.

예를 들어,이 라인 : 그것은 많은이 매년 섹션과 질문에 대한 데이터베이스를 타격하기 때문에

var answer = db.Answers.Where(l => l.QuestionID == question.QuestionID && l.OrganisationID == section.OrganisationID && l.FinancialYearID == financialYear.FinancialYearID).FirstOrDefault(); 

은 아마 성능 문제입니다. 단일 쿼리로 모든 것을 메모리에 미리로드하고 메모리 내 데이터로 작업하는 것이 좋습니다.

또한 언급하지 않았습니다. 어떤 종류의 성능 최적화를 시도하기 전에 코드을 프로파일해야합니다. 이 방법을 사용하면 문제가 I/O 바운드인지 또는 알고리즘인지 알 수 있습니다. 그러면 코드를 최적화해야합니다.

+0

팁 주셔서 감사. 나는이 데이터베이스 세트를 메모리에 넣고'db '대신에 콜렉션을 사용하려고 시도했다. 이상하게도이 방법은이 방법을 실행하는 데 더 오래 걸렸다. 예상대로 RAM 사용량이 많이 증가했지만 성능은 향상되지 않았습니다. 또한 ANTS 프로파일 러를 사용해 보겠습니다. 감사합니다. – user982119

+0

@ user982119 이상하네요. 수정 된 코드를 게시 할 수 있습니까? – Euphoric

+0

이제 코드를 올바르게 볼 때 간단한 쿼리 하나만으로 해결할 수 있습니다. – Euphoric

관련 문제