2017-01-29 2 views
0

В настоящее время я изучаю C#, и я работал над парсером XML за последние два дня. Это действительно работает, моя проблема - это количество времени, затрачиваемого на анализ более 10 тыс. Страниц. это мой код.C# Запуск всей темы за один раз при разборе

public static void startParse(int id_min, int id_max, int numberofthreads) 
    { 
     int start; 
     int end; 
     int part; 
     int threadnbrs; 

     threadnbrs = numberofthreads; 
     List<Thread> workerThreads; 
     List<string> results; 

     part = (id_max - id_min)/threadnbrs; 
     start = id_min; 
     end = 0; 
     workerThreads = new List<Thread>(); 
     results = new List<string>(); 

     for (int i = 0; i < threadnbrs; i++) 
     { 
      if (i != 0) 
       start = end + 1; 
      end = start + (part); 
      if (i == (threadnbrs - 1)) 
       end = id_max; 

      int _i = i; 
      int _start = start; 
      int _end = end; 

      Thread t = new Thread(() => 
      { 

        Console.WriteLine("i = " + _i); 
        Console.WriteLine("start =" + _start); 
        Console.WriteLine("end =" + _end + "\r\n"); 
        string parse = new ParseWH().parse(_start, _end); 
        lock (results) 
        { 
         results.Add(parse); 
        } 
      }); 
      workerThreads.Add(t); 
      t.Start(); 
     } 
     foreach (Thread thread in workerThreads) 
       thread.Join(); 

     File.WriteAllText(".\\result.txt", String.Join("", results)); 
     Console.Beep(); 
    } 

то, что я на самом деле делать это расщепление в другом потоке ряд элементов, которые должны быть разобраны так каждый дескриптор потока элементов X.

для каждых 100 элементов занимает около 20 секунд. однако мне понадобилось 17 минут для разбора 10 0000 элементов.

что мне нужно, каждая нить работает одновременно на 100 из этих 10 000 элементов, поэтому это можно сделать за 20 секунд. есть ли для этого решение?

Анализировать Код:

public string parse(int id_min, int id_max) 
     { 
      XmlDocument xml; 
      WebClient user; 
      XmlElement element; 
      XmlNodeList nodes; 
      string result; 
      string address; 
      int i; 

      //Console.WriteLine(id_min); 
      //Console.WriteLine(id_max); 
      i = id_min; 
      result = ""; 
      xml = new XmlDocument(); 
      while (i <= id_max) 
      { 
       user = new WebClient(); 
       // user.Headers.Add("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.0.3; ko-kr; LG-L160L Build/IML74K) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"); 
       user.Encoding = UTF8Encoding.UTF8; 
       address = "http://fr.wowhead.com/item=" + i + "?xml"; 
       if (address != null) 
        xml.LoadXml(user.DownloadString(new Uri(address))); 
       element = xml.DocumentElement; 
       nodes = element.SelectNodes("/wowhead"); 
       if (xml.SelectSingleNode("/wowhead/error") != null) 
       { 
        Console.WriteLine("error " + i); 
        i++; 
        continue; 
       } 
       result += "INSERT INTO item_wh (entry, class, subclass, displayId, ,quality, name, level) VALUES ("; 
       foreach (XmlNode node in nodes) 
       { 
        // entry 
        result += node["item"].Attributes["id"].InnerText; 
        result += ", "; 
        // class 
        result += node["item"]["class"].Attributes["id"].InnerText; 
        result += ", "; 
        // subclass 
        result += node["item"]["subclass"].Attributes["id"].InnerText; 
        result += ", "; 
        // displayId 
        result += node["item"]["icon"].Attributes["displayId"].InnerText; 
        result += ", "; 
        // quality 
        result += node["item"]["quality"].Attributes["id"].InnerText; 
        result += ", \""; 
        // name 
        result += node["item"]["name"].InnerText; 
        result += "\", "; 
        // level 
        result += node["item"]["level"].InnerText; 
        result += ");"; 
        // bakcline 
        result += "\r\n"; 
       } 
       i++; 
      } 
      return (result); 
     } 
+3

Таким образом, для анализа 100 элементов требуется 20 секунд ... как вы ожидаете получить пропускную способность 1000x, разобрав в 1000 раз столько элементов за такое же количество времени? Threading не просто волшебным образом дает вам свободную вычислительную мощность или пропускную способность сети (мы не знаем, что занимает время для 100 элементов). –

+0

@JonSkeet - но добавление потоков позволит им получить доступ к нескольким процессорным ядрам, тогда как при этом линейно будет использовать только одно ядро ​​максимум. На многоядерной машине нарезание резьбы приведет к увеличению количества ядер в процедуре. Согласитесь полностью, что проблема заключается в времени, затрачиваемом на разбор 100 предметов, которые являются чрезмерно чрезмерными. – PhillipH

+1

@PhillipH На типичном современном компьютере с, скажем, 8 ядрами, вы бы в абсолютном максимуме получили ускорение 7-8x, а не 1000x. В качестве побочного примечания, другие вещи быстро становятся узким местом (например, сетевым или дисковым IO). Вам лучше профилировать свой код, чтобы узнать, почему ваш синтаксический анализ длится так долго и исправить это. –

ответ

0

Хорошо, поэтому я нашел «Trying to run multiple HTTP requests in parallel, but being limited by Windows (registry)» это называется «Пул потоков» I наконец, решил напрямую загрузить XML-файл, а затем проанализировать документ непосредственно в автономном режиме, вместо того, чтобы разбору веб-сайта напрямую получить формат SQL. новый метод работы, я могу загрузить и записать до 10 000 K XML всего за 9 секунд. Я попытался подтолкнуть его к 150 К (все страницы веб-сайтов), но теперь у меня есть странная ошибка, у меня есть элементы дубликатов ... Я попытаюсь переписать полный код, используя правильный метод для пулов, multi Task/Thread, словарь и IEnumerable Containers перетаскивают палец, чтобы работать на 150 k. Элемент, не теряя данные в процессе и отправляя полный код.

0

Лучшее решение для процессора связаны работы (такие, как разборе), чтобы запустить столько потоков, сколько числа ядер в вашей машине, меньше, чем это, и вы не пользуясь из всех ваших ядер, более того, и чрезмерное переключение контекста может привести к снижению производительности.

Так, по существу, threadnbrs должен быть установлен в Environment.ProcessorCount

Кроме того, рассмотреть возможность использования параллельного класса, а не создавать темы с себя:

Parallel.ForEach(thingsToParse, (somethingToParse) => 
     { 
      var parsed = Parse(somethingToParse); 
      results.Add(parsed); 
     }); 

Вы должны согласиться, что это выглядит намного чище и гораздо проще поддерживать. Кроме того, вам будет лучше использовать ConcurrentBag вместо обычной блокировки List +, поскольку ConcurrentBag больше построен для одновременных нагрузок и может дать вам лучшую производительность.

0

Наконец-то! Получил его работу, одновременно запуская несколько процессов моего приложения.

Ведьма означает, что если у меня есть 10 k элементов, я запускаю 10 процессов из 1000 элементов. увеличить количество процессов, чтобы уменьшить количество элементов, и оно идет быстрее и быстрее! (я в настоящее время работает на очень быстрой скорости Интернета) и имею Samsung M.2 960 как хранилище, а также ядро ​​I7 Skylake 6 ядер

Смежные вопросы