Высокая производительность умножения / оценки в C # - PullRequest
3 голосов
/ 24 марта 2011

Извините за смутное название темы; Трудно кратко описать мой вопрос.

У меня есть коллекция большого количества объектов (пара тысяч), определенная как ...

public class Item
{
    public int ID;
    public float A;
    public float B;
    public float C;
    public float D;
    public float E;
    public float F;
    public float G;
}

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

Например, у меня сейчас что-то вроде ...

public Item FindLargest(float aMult, float bMult, float cMult, float dMult, float eMult, float fMult, float gMult)
{
    Item largest = null;
    float largestTotal = 0f;
    foreach(Item item in ItemsCollection)
    {
        float total = item.A * aMult + 
                      item.B * bMult + 
                      item.C * cMult + 
                      item.D * dMult + 
                      item.E * eMult + 
                      item.F * fMult + 
                      item.G * gMult;
        if (total > largestTotal)
        {
            largest = item;
            largestTotal = total;
        }
    }
    return largest;
}

Производительность этого недостаточна, и поэтому мне интересно, могу ли я что-нибудь сделать, чтобы реструктурировать данные таким образом, заблаговременно, чтобы вызов FindLargest был намного быстрее. Некоторое время я делал это так, и производительность была хорошей: ~ 40-50 элементов в ItemsCollection, но теперь дизайн другой части моего приложения изменился, и, как побочный продукт, мне нужно обработать гораздо больший набор данных (~ 2000, а не ~ 50), поэтому я заинтересован в дальнейшей оптимизации. Спасибо за любую помощь, которую может предложить каждый!

РЕДАКТИРОВАТЬ: Я должен был упомянуть об этом для начала: я уже распараллеливать это в том, что то, что вызывает это, уже сильно распараллелены. И то, что вызывает это, действительно вызывает это много раз, со многими различными параметрами, очень быстро. Каждый раз, когда значение изменяется в открытом документе в моем приложении, его нужно вызывать около ста раз, и оно должно быть «отзывчивым» (уже выполняются все вычисления в нескольких фоновых потоках, поэтому я не имею в виду блокировку пользовательского интерфейса) .

РЕДАКТИРОВАТЬ 2: См. Мои комментарии в принятом ответе.

Ответы [ 4 ]

5 голосов
/ 24 марта 2011

Я не думаю, что проблема с вашей функцией здесь.Я потратил меньше 0,1 секунды, чтобы завершить функцию с 500 000 элементов в коллекции.

Возможно, вы захотите найти способ оптимизировать часть кода, которая вызывает эту функцию.Использование PLINQ на этом уровне должно дать лучшие результаты.

5 голосов
/ 24 марта 2011

Один вариант использует PLINQ для использования нескольких ядер.

        var result = (from item in ItemsCollection
                      let total = item.A * aMult + 
                                  item.B * bMult + 
                                  item.C * cMult + 
                                  item.D * dMult + 
                                  item.E * eMult + 
                                  item.F * fMult + 
                                  item.G * gMult
                      select new {item, total}).AsParallel().Max(i => i.total);
1 голос
/ 24 марта 2011

Рассмотрите возможность использования Parallel.ForEach при выполнении умножения выше.Вы также можете рассмотреть возможность реализации справочной таблицы в виде словаря, содержащего Item.ID и его общее количество.Поэтому, когда умножение завершено, вы можете использовать LINQ, чтобы отсортировать и собрать элемент с наибольшим количеством.Что-то вроде:

var sortedItems = from item in ItemsTotalsDictionary orderby item.Value descending select item.Key;

1 голос
/ 24 марта 2011

Разделите ваш набор данных на 6 непрерывных диапазонов.Присвойте каждый диапазон другому потоку, который запускается асинхронно, чтобы вычислить наибольшее значение.Когда все темы будут готовы, у вас будет 6 различных предметов - по одному от каждого диапазона.Перейдите через 6, чтобы найти тот, который является самым большим для всего набора данных.

Есть и другие способы оптимизации, которые вы можете выполнить.

Вместо того, чтобы запускать потоки .NET самостоятельно, вы можете просто кодировать, используя библиотеку Microsoft PLINQ

...