ConcurrentDictionary: супер медленно? - PullRequest
0 голосов
/ 13 октября 2010

У меня есть файл, который я пытаюсь проанализировать, и вот как я это делаю:

var definitions = new Dictionary<int, string>();

foreach (var line in new RirStatFile("delegated-lacnic-latest.txt"))
{
    for (var i = 0; i < line.Range; i ++)
    {
        definitions[line.StartIpAddress + i] = line.Iso3166CountryCode;
    };
};

new RirStatFile(...) возвращает IEnumerable<RirStatFileLine>() с .Count из 4 100 RirStatFileLine объектов, где каждый RirStatFileLine имеет .Range, значение которого обычно составляет от 32768 до 1 миллиона.

Выполнение этого, как показано в фрагменте выше, занимает около 45 секунд на моем жалком нетбуке.

РЕДАКТИРОВАТЬ: двухъядерный нетбук.

Отличное место для использования новой библиотеки параллельных задач, верно? Я так и думал, поэтому я изменил код на:

var definitions = new ConcurrentDictionary<int, string>();

Parallel.ForEach(new RirStatFile("delegated-lacnic-latest.txt"), line => 
{
    Parallel.For(0, line.Range, i =>
    {
        definitions[line.StartIpAddress + i] = line.Iso3166CountryCode;
    });
});

И угадайте что? Программа занимает 200 секунд!

Что дает? Очевидно, я не понимаю, что здесь происходит. Просто для справки, вот RirStatFileLine:

public class RirStatFileLine
{
    public readonly string Iso3166CountryCode;
    public readonly int StartIpAddress;
    public readonly int Range;

    public RirStatFileLine(string line)
    {
        var segments = line.Split('|');

        // Line:         
        //    lacnic|BR|ipv4|143.54.0.0|65536|19900828|assigned
        // Translation:
        //    rir_name|ISO_countryCode|ipVersion|ipAddress|range|dateStamp|blah

        this.Iso3166CountryCode = segments[1];
        this.StartIpAddress =
         BitConverter.ToInt32(IPAddress.Parse(segments[3]).GetAddressBytes(), 0);
        this.Range = int.Parse(segments[4]);
    }
}

И RirStatFile:

public class RirStatFile : IEnumerable<RirStatFileLine>
{
    private const int headerLineLength = 4;

    private readonly IEnumerable<RirStatFileLine> lines;

    public RirStatFile(string filepath)
    {
        this.lines = File.ReadAllLines(filepath)
                         .Skip(RirStatFile.headerLineLength)
                         .Select(line => new RirStatFileLine(line)); 
    }

    public IEnumerator<RirStatFileLine> GetEnumerator()
    {
        return this.lines.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.lines.GetEnumerator();
    }
}

Ответы [ 2 ]

4 голосов
/ 13 октября 2010

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

Вы должны распараллелить вычислительно дорогой код, а не тривиальный код.

Кроме того, выReadAllLines вместо ReadLines, поэтому нет никакой возможности для какой-либо обработки перекрываться с чтением файла.

MSDN "Методы ReadLines и ReadAllLines отличаются следующим образом: Когда вы используете ReadLines,Вы можете начать перечисление коллекции строк до того, как будет возвращена вся коллекция; при использовании ReadAllLines необходимо дождаться возврата всего массива строк, прежде чем вы сможете получить доступ к массиву. Поэтому, когда вы работаете с очень большими файлами, ReadLinesможет быть более эффективным. "

0 голосов
/ 13 октября 2010

Проблема здесь в том, что ваш нетбук имеет только один процессор / ядро ​​/ аппаратный поток.Здесь паралич совершенно не поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...