2014-12-03 1 views
1

인터넷에서 데이터를 다운로드하고 데이터베이스에 저장하는 메서드를 작성했습니다. 필자는 PLINQ를 사용하여 멀티 코어 프로세서를 활용하고 매우 짧은 기간에 수천 개의 서로 다른 파일을 다운로드하기 때문에이를 작성했습니다. 아래 코드를 주석에 추가하여 프로그램이 멈추는 위치를 보여 주지만 프로그램이 거기에 앉아 잠시 후 메모리 부족 문제가 발생합니다. 이것은 TPL과 PLINQ를 처음 사용하는 것이므로 극도로 혼란스러워서 이것을 해결하기 위해해야 ​​할 일에 대한 조언을 할 수 있습니다.처음으로 병렬 linq를 사용하고 메모리 부족 예외가 발생하는 메서드를 만드는 중

업데이트 : 웹 클라이언트가 시간 초과되어 끊임없이 웹 예외가 발생한다는 것을 알았습니다. this answer here에 따라 최대 연결 수를 늘려이 문제를 해결했습니다. 그런 다음 연결이 열리지 않는 예외를 얻었으며 this answer here을 사용하여 해결했습니다. 지금은 로컬 SQL 서버이지만 데이터베이스에 대한 연결 시간 초과 오류가 발생합니다. 그들은 기적으로 완료되지 않지만 그들은 작업을 반환 : 나는 아직도 내가 완전히

static void Main(string[] args) 
    { 
     try 
     { 
      while (true) 
      { 
       // start the download process for market info 
       startDownload(); 
      } 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.Message); 
      Console.WriteLine(ex.StackTrace); 
     } 
    } 

    public static void startDownload() 
    { 
     DateTime currentDay = DateTime.Now; 
     List<Task> taskList = new List<Task>(); 

     if (Helper.holidays.Contains(currentDay) == false) 
     { 
      List<string> markets = new List<string>() { "amex", "nasdaq", "nyse", "global" }; 

      Parallel.ForEach(markets, market => 
      { 
       Downloads.startInitialMarketSymbolsDownload(market); 
      } 
      ); 

      Console.WriteLine("All downloads finished!"); 
     } 

     // wait 24 hours before you do this again 
     Task.Delay(TimeSpan.FromHours(24)).Wait(); 
    } 

public static void startInitialMarketSymbolsDownload(string market) 
    { 
     try 
     { 
      List<string> symbolList = new List<string>(); 
      symbolList = Helper.getStockSymbols(market); 

      var historicalGroups = symbolList.AsParallel().Select((x, i) => new { x, i }) 
         .GroupBy(x => x.i/100) 
         .Select(g => g.Select(x => x.x).ToArray()); 

      historicalGroups.AsParallel().ForAll(g => getHistoricalStockData(g, market)); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.Message); 
      Console.WriteLine(ex.StackTrace); 
     } 
    } 

public static void getHistoricalStockData(string[] symbols, string market) 
    { 
     // download data for list of symbols and then upload to db tables 
     Uri uri; 
     string url, line; 
     decimal open = 0, high = 0, low = 0, close = 0, adjClose = 0; 
     DateTime date; 
     Int64 volume = 0; 
     string[] lineArray; 
     List<string> symbolError = new List<string>(); 
     Dictionary<string, string> badNameError = new Dictionary<string, string>(); 

     Parallel.ForEach(symbols, symbol => 
       { 
         url = "http://ichart.finance.yahoo.com/table.csv?s=" + symbol + "&a=00&b=1&c=1900&d=" + (DateTime.Now.Month - 1) + "&e=" + DateTime.Now.Day + "&f=" + DateTime.Now.Year + "&g=d&ignore=.csv"; 
         uri = new Uri(url); 

         using (dbEntities entity = new dbEntities()) 
         using (WebClient client = new WebClient()) 
         using (Stream stream = client.OpenRead(uri)) 
         using (StreamReader reader = new StreamReader(stream)) 
         { 
          while (reader.EndOfStream == false) 
          { 
           line = reader.ReadLine(); 
           lineArray = line.Split(','); 

           // if it isn't the very first line 
           if (lineArray[0] != "Date") 
           { 
            // set the data for each array here 
            date = Helper.parseDateTime(lineArray[0]); 
            open = Helper.parseDecimal(lineArray[1]); 
            high = Helper.parseDecimal(lineArray[2]); 
            low = Helper.parseDecimal(lineArray[3]); 
            close = Helper.parseDecimal(lineArray[4]); 
            volume = Helper.parseInt(lineArray[5]); 
            adjClose = Helper.parseDecimal(lineArray[6]); 

            switch (market) 
            { 
             case "nasdaq": 
              DailyNasdaqData nasdaqData = new DailyNasdaqData(); 
              var nasdaqQuery = from r in entity.DailyNasdaqDatas.AsParallel().AsEnumerable() 
                   where r.Date == date 
                   select new StockData { Close = r.AdjustedClose }; 

              List<StockData> nasdaqResult = nasdaqQuery.AsParallel().ToList(); // hits this line 
              break; 
             default: 
              break; 
            } 
           } 
          } 

          // now save everything 
          entity.SaveChanges(); 
         } 
       } 
     ); 
    } 
+0

너무 많은 코드. 특히 적중하지 않은 것으로 표시된 코드는 삭제하십시오. – usr

+0

@usr 읽기 쉽도록 코드를 삭제했지만 더 이상 삭제할 수 없습니다. 나는 분명히 내 이슈의 전체 초점이기 때문에 결코 치지 않는 코드를 삭제할 수 없다. – user3610374

답변

2

비동기 람다 한 점에서 비동기 방식처럼 작동 몇 가지 조언을 사용할 수 있습니다 실행하는 내 코드 중 하나를 얻을 수 없었다. 병렬 루프에서는 가능한 한 빨리 작업을 생성합니다. 이러한 작업은 메모리 및 DB 연결과 같은 다른 리소스를 유지합니다.

가장 간단한 해결 방법은 동기식 데이터베이스 커밋을 사용하는 것입니다. 데이터베이스가 많은 양의 동시 DML을 처리 할 수 ​​없으므로 처리량이 손실되지 않습니다.

+0

당신이 말하는 것은 의미가 있으며 나는 그 변화를 만들었지 만 if (linearray [0]) 라인에서 중단 점을 위해 10 분이 걸린다. 나는 프로그램을 시작한 순간부터이 메소드를 호출하여 어딘가에 뭔가를 망가 뜨리는 지 확인하기 위해 코드를 포함하도록 편집 할 것이다. – user3610374

+0

하나 이상한 일은 내가 처리하는 코드의 유일한 줄은 URL이 유효하지 않은 경우 웹 예외가 발생하는 경우입니다. 그 메서드에서 다른 코드 줄을 칠 수는 없습니다 ... – user3610374

+0

구성 모든 병렬 처리 프리미티브는 MaxDOP 1을 사용하여 단일 스레드 방식으로 디버깅 할 수 있습니다 .3 개의 중첩 된 병렬 루프는 많은 중첩 작업을 수행하므로 DB (pool)와 같은 일부 IO 하위 시스템을 압도 할 수있는 많은 스레드가 발생할 수 있습니다. 고갈) 및 웹 (connectio n 및 서버 한도). – usr

관련 문제