-3

Parallel.Foreach를 사용하는 경우에도 7 분 이상 완료되는 flollowing 코드가 있습니다. 필자가 반복하는 "final_products"목록에는 약 7000 개의 제품이 포함되어 있습니다.Parallel.Foreach는 너무 느립니다. 코드 최적화 방법

public void GenerateTreeFromAllFinalProducts() 
    { 
     XmlSerializer serializer = new XmlSerializer(typeof(ImageFeature<float>[])); 
     DSTableAdapters.Products_UniqueTableAdapter pft = new DSTableAdapters.Products_UniqueTableAdapter(); 
     DSTableAdapters.Products_Unique_SURFTableAdapter pus = new DSTableAdapters.Products_Unique_SURFTableAdapter(); 
     DS.Products_UniqueDataTable final_products = pft.GetData(); 

     Stopwatch stopwatch = new Stopwatch(); 
     stopwatch.Start(); 

     Parallel.ForEach(final_products.AsParallel(), row => 
     {     
      //Get SURF data for all images found similar to this image 
      Types.Products_Unique_SURFRow surfData = GetDataByUniqueProductID(row.id); 

      ImageFeature<float>[] row_features = (ImageFeature<float>[])serializer.Deserialize(new StringReader(Decompress(surfData.SURF))); 
      if (row_features != null) 
       flann.AddSurfDescriptors(row_features, row.id);      
     }); 

     stopwatch.Stop(); 
     Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed); 
    } 

이 긴 시간이 걸리므로 정상적으로 코드를 최적화 할 수 있습니까?

GetDataByUniqueProductID (row.id)는 하나의 단일 행을 반환하는 데이터베이스에 대한 호출입니다. 나는 Parallel.Foreach을하려고 노력하는 이유 즉,

private static Types.Products_Unique_SURFRow GetDataByUniqueProductID(int rowid) 
    { 
     Types.Products_Unique_SURFRow ret = new Types.Products_Unique_SURFRow(); 

     string sqlText = "SET ROWCOUNT 1 SELECT SURF from Products_Unique_SURF WHERE unique_product_id =" + rowid; 

     using (SqlConnection myConn = new SqlConnection(global::SCBot.Properties.Settings.Default.DataConnectionString)) 
     { 
      myConn.Open(); 

      SqlCommand cmd = new SqlCommand(sqlText, myConn); 
      try 
      { 
       cmd.CommandType = CommandType.Text; 

       SqlDataReader reader = cmd.ExecuteReader(); 
       while (reader.Read()) 
       { 
        Types.Products_Unique_SURFRow row = new Types.Products_Unique_SURFRow(); 
        row.SURF = Convert.ToString(reader["SURF"]); 

        ret = row; 
       } 
      } 
      catch (Exception e) 
      { 
       MessageBox.Show(e.ToString()); 
      } 
     } 
     return ret; 
    } 

내 초기 코드는 다음

public void GenerateTreeFromAllFinalProducts() 
    { 
     XmlSerializer serializer = new XmlSerializer(typeof(ImageFeature<float>[])); 
     DSTableAdapters.Products_UniqueTableAdapter pft = new DSTableAdapters.Products_UniqueTableAdapter(); 
     DSTableAdapters.Products_Unique_SURFTableAdapter pus = new DSTableAdapters.Products_Unique_SURFTableAdapter(); 
     DS.Products_UniqueDataTable final_products = pft.GetData(); 

     foreach (DS.Products_UniqueRow row in final_products) 
     { 
      //Get SURF data for all images found similar to this image 
      List<DS.Products_Unique_SURFRow> surfData = pus.GetDataByUniqueProductID(row.id).ToList(); 

      foreach (DS.Products_Unique_SURFRow data in surfData) 
      { 
       ImageFeature<float>[] row_features = (ImageFeature<float>[])serializer.Deserialize(new StringReader(Decompress(data.SURF))); 
       flann.AddSurfDescriptors(row_features, row.id); 
      } 
     } 
    } 

했다 그러나이 너무 느렸다

당신은 시간을 측정한다

답변

0

는 내부 코드가 필요 . Parallel은 내부 코드의 속도를 높이 지 못합니다. Decompress/Deserialize 메서드를 중첩하는 대신 별도로 측정 할 수 있습니다.

편집 후 :

각 스레드는 새로운 연결을 생성합니다. 나는 이것이 위의 예제라고 생각한다. 은 속도를 높이기 위해 평행을 사용하는 것이 아니다. 그러나 알고리즘을 변경하면 더 많은 도움이 될 것입니다. 서로 다른 연결/스레드에서 단일 행을 쿼리하는 것이 쿼리 전체 (또는 선택 사항)와 단일 스레드 된 foreach를 반복하는 것보다 많은 시간이 소요됩니다.

내보기 :

나는 final_products의 enemration 및 축적의 모든 아이디의 StringBuilder 내를 사용하여 문자열을 수집하는 것입니다.

StringBuilder sb = new StringBuiler(); 
bool isFirst = true; 

sb.Append("("); 
foreach(var prod in final_products) 
{ 
    if(isFirst) 
     isFirst = false; 
    else 
     sb.Append(", "); 

    sb.Append(prod.Id); 
} 
sb.Append(")"); 

string query = "SELECT SURF FROM Products_Unique_SURF WHERE Id in "+sb.ToString(); 

// execute the query 

// foreach row, decompress, deserialize etc... 
+0

그래서 내가 말하고자하는 것은 하나의 쿼리에서 SURF 데이터의 전체 목록을 가져 와서 parellel을 실행해야한다는 것입니다. – user2663850

+0

대부분의 경우 코드가 데이터를 연결/쿼리하기 때문에 Parallel이 필요하다고 생각하지 않습니다. 나는 Decompressize/Deserialize가 매우 느리다 고 생각하지 않는다. Decompress/Deserialize가 느린 경우 병렬 처리를 사용할 수 있지만 단일 행을 쿼리하지 않도록해야합니다. –

+0

정확합니다. 압축 풀기/역 직렬화가 느립니다. 시간이 오래 걸리는 것은 7000 개의 제품을 반복하고 단일 SURF 행을 얻는 것입니다. – user2663850