Что быстрее: соответствующий ввод данных или соответствующая структура данных? - PullRequest
5 голосов
/ 20 мая 2010

У меня есть набор данных, столбцы которого выглядят так:

Consumer ID | Product ID | Time Period | Product Score
1           | 1          | 1           | 2
2           | 1          | 2           | 3

и т. Д.

В рамках программы (написанной на C) мне нужно обработать оценки продуктов, заданные всеми потребителями для определенной комбинации продуктов и периодов времени для всех возможных комбинаций. Предположим, что есть 3 продукта и 2 периода времени. Затем мне нужно обработать оценки продуктов для всех возможных комбинаций, как показано ниже:

Product ID | Time Period 
1          | 1
1          | 2
2          | 1
2          | 2
3          | 1
3          | 2

Мне нужно будет обрабатывать данные по вышеуказанным линиям много раз (> 10 КБ), и набор данных достаточно велик (например, 48 000 потребителей, 100 продуктов, 24 периода времени и т. Д.). Так что скорость это проблема.

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

  1. Сортировка данных по идентификатору продукта и периоду времени, а затем цикл по данным для извлечения данных для всех возможных комбинаций.

  2. Сохраните идентификаторы потребителей всех потребителей, которые предоставили оценки продуктов для конкретной комбинации идентификатора продукта и периода времени, и обработайте данные соответствующим образом.

Есть мысли? Есть ли другой способ ускорить обработку? Спасибо

Ответы [ 7 ]

3 голосов
/ 20 мая 2010

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

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

0 голосов
/ 20 мая 2010

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

Также взгляните на Нормализация базы данных . Это концепция организации данных с минимальным дублированием, а также делает доступ к данным более эффективным.

Другая идея заключается в использовании индексов для менее популярных поисков данных.

0 голосов
/ 20 мая 2010

Если позволяет память, сохраняйте ваши данные в 2-мерном массиве (действительно в 3D, но я вернусь к этому позже).Этот массив будет проиндексирован с помощью (product_id, time_period).

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

Если ваша обработка требует, чтобы вы представляли данные из каждого элемента данных одновременно, тогда вы можете сделать каждый элемент вашего 2D-массива списком(это 3-й D).Это может быть список переменной длины, если вы не знаете, сколько записей клиентов будет присутствовать для каждого (product_id, time_period).После того, как вы прочитали свои данные, вам нужно будет вернуться к каждому элементу двумерного массива, чтобы обработать каждый список.То, как вы расположите свой массив и как вы посещаете элементы, будет иметь значение для производительности.Возможно, вы захотите объявить это динамически, но для этого примера

struct element_t element[NUMBER_OF_PRODUCTS][NUMBER_OF_TIME_PERIODS];
// don't forget to initialize these elements to empty
...
for (p = max_product_id; p >= 0; p--) {
    for (t = max_time_period; t >= 0; t--) {
         process(element[p][t]);
    }
}

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

Следует отметить, что это выполняет сортировку дляВы не говорите «сортировать эти данные».

Если память не позволяет, то вы, вероятно, захотите сохранить части ваших данных в файлы, когда вы их читаете. Это будет иметь те же проблемы, что и массив /Упомянутая выше оптимизация циклической организации / попадания в кэш, но она будет увеличена во много раз.В конце чтения ваших основных данных вы захотите иметь возможность обработать все данные из определенного временного файла (возможно, содержащего все данные для данного продукта (xOR за определенный период времени)) перед переходом к следующему.Основная плохая часть попытки сделать это состоит в том, что когда вы читаете данные, очень вероятно, что вам придется иметь дело с невозможностью открыть все временные файлы одновременно.Это может потребовать, чтобы вы нашли способ сделать открытый обмен файлами (такой же, как обмен памятью, за исключением того, что вы меняете местами файлы, а не страницы памяти).Это была бы совсем другая проблема.

0 голосов
/ 20 мая 2010

Самая медленная часть, на которую вы оказываете влияние, вероятно, будет копировать куски памяти. Таким образом, первый метод, который нужно применить, - поместить значения для каждой строки в структуру и обращаться к ней только по указателю, пока вся обработка не будет завершена. Структуры будут выглядеть примерно так:

typedef struct {
 int consumer;
 int product;
 int time;
 int score;
} rowData;

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

typedef struct {
 int consumer;
 int product;
 rowData * matches;
} matchLut;

После размещения всех строк в таблицах поиска на дереве можно обрабатывать каждый пакет.

0 голосов
/ 20 мая 2010

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

Можете ли вы обменять пространство на время? Если да, то не выполняйте никакой предварительной обработки, но создайте массив всех комбинаций (10x24) для хранения результатов. Обработайте данные по мере их поступления и обновите счет конкретной комбинации. Если вам нужен средний балл, сохраните сумму и количество клиентов, предоставивших балл.

0 голосов
/ 20 мая 2010

Это сделало бы для маленькой таблицы базы данных.Это около 0,4 ГБ данных, если существует полная матрица потребителей / продуктов / времени.Рассматривали ли вы запустить все это в SQL?Даже если вы не используете полную базу данных;для данных такого размера было бы целесообразно сгенерировать полную таблицу для каждого из возможных порядков сортировки и вывести каждый из них в файл.Затем вы можете загрузить любой файл, который вам нужен, чтобы пройти его в любом порядке, который вы выберете.

Кроме того, если вы можете выполнять полные 10К проходов параллельно или, по крайней мере, несколько десятков за проход, вы можете сделать это заранее.так как это может значительно сократить время ожидания ввода-вывода и / или потери кэша.

0 голосов
/ 20 мая 2010

Я бы посоветовал отфильтровать данные, как на втором шаге, а затем обработать в соответствии с первым шагом Если ваша производительность неприемлема, настройтесь на производительность. Установите некоторые критерии для вашей базовой линии, затем попробуйте несколько других подходов.

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

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