Подтвердить что ты не робот

Можно ли ускорить (динамический) запрос LINQ с помощью GPU?

Я искал несколько дней для получения достоверной информации о возможности ускорения запросов LINQ с использованием графического процессора.

Технологии, которые я исследовал до сих пор:

  • Microsoft Accelerator
  • Cudafy
  • Брахма

Короче говоря, возможно ли вообще вообще сделать фильтрацию объектов на GPU в памяти?

Предположим, у нас есть список некоторых объектов, и мы хотим отфильтровать что-то вроде:

var result = myList.Where(x => x.SomeProperty == SomeValue);

Любые указатели на этом?

Спасибо заранее!

UPDATE

Я постараюсь более конкретно узнать, чего я пытаюсь достичь:)

Цель состоит в том, чтобы использовать любую технологию, которая может фильтровать список объектов (от ~ 50 000 до ~ 2 000 000) самым быстрым способом.

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

Узким местом является "просто" фильтрация данных.

UPDATE

Просто захотелось добавить, что я тестировал около 15 баз данных, включая MySQL (проверка возможного подхода к кластеру/решение memcached), H2, HSQLDB, VelocityDB (в настоящее время исследует далее), SQLite, MongoDB и т.д., и NONE достаточно хорош, когда приходит к скорости фильтрации данных (конечно, NO-sql-решения не предлагают такого, как sql-те, но вы получаете идею) и/или возврат фактических данных.

Просто подытожим то, что мне нужно:

База данных, способная сортировать данные в формате 200 столбцов и около 250 000 строк менее чем за 100 мс.

В настоящее время у меня есть решение с параллелизированным LINQ, которое может (на определенной машине) тратить только nano -секунды на каждую строку при фильтрации И обработки результата!

Итак, нам нужна суб- nano -секундная фильтрация для каждой строки.

  • Почему кажется, что только в памяти LINQ может это предоставить?
  • Почему это невозможно?

Некоторые цифры из файла журнала:

Total tid för 1164 frågor: 2579

Это шведский и переводит:

Total time for 1164 queries: 2579

Если запросы в этом случае являются запросами типа:

WHERE SomeProperty = SomeValue

И эти запросы выполняются в параллельном порядке по 225639 строкам.

Итак, 225639 строк фильтруются в памяти 1164 раза за 2,5 секунды.

Это 9,5185952917007032597107300413827e-9 секунд/строка, НО, что также включает фактическую обработку чисел! Мы делаем Count (не null), общее количество, Sum, Min, Max, Avg, Median. Итак, у нас есть 7 операций над этими отфильтрованными строками.

Итак, мы могли бы сказать, что это на самом деле в 7 раз быстрее, чем в базах данных, которые мы пробовали, поскольку мы делаем НЕ любые агрегирующие материалы в этих случаях

Итак, в заключение, почему базы данных настолько плохи при фильтрации данных по сравнению с фильтрацией LINQ в памяти? Действительно ли Microsoft сделала такую ​​хорошую работу, что с ней невозможно конкурировать?:)

Это имеет смысл, хотя фильтрация в памяти должна быть быстрее, но мне не нужен смысл, что он быстрее. Я хочу знать, что быстрее, и если возможно , почему.

4b9b3361

Ответ 1

Я окончательно отвечу о Брахме, так как это моя библиотека, но она, вероятно, относится и к другим подходам. Графический процессор не знает объектов. Эта память также в основном полностью отделена от памяти ЦП.

Если у вас есть БОЛЬШОЙ набор объектов и вы хотите работать с ними, вы можете упаковать только те данные, которые хотите работать, в буфер, подходящий для используемого вами графического процессора /API, и отправить его для обработки,

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

Надеюсь, что это поможет.

Ответ 2

Графический процессор действительно не предназначен для всех целей общего назначения, особенно с объектно-ориентированными проектами, подобными этому, и фильтрация произвольного набора данных, подобных этому, действительно не подходит.

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

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

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

var result = myList.AsParallel().Where(x => x.SomeProperty == SomeValue);

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

Ответ 3

GpuLinq

Основная задача GpuLinq - демократизировать программирование GPGPU через LINQ. Основная идея заключается в том, что мы представляем запрос как дерево выражений, а после различных преобразований-преобразований мы скомпилируем его в быстрый код ядра OpenCL. Кроме того, мы предоставляем очень простой в работе API без необходимости возиться с деталями API OpenCL.

https://github.com/nessos/GpuLinq

Ответ 4

Простой ответ для вашего случая использования - нет.

1) Нет решения для такого рода рабочей нагрузки, даже в необработанном linq для объекта, а тем более в чем-то, что заменит вашу базу данных.

2) Даже если вы были в порядке с загрузкой всего набора данных одновременно (это требует времени), все равно будет намного медленнее, так как у GPU высокая пропускная способность, но их доступ имеет высокую задержку, поэтому, если вы смотрите на "очень" быстрые решения" GPGPU часто не являются ответом, так как просто подготовка/отправка рабочей нагрузки и возвращение результатов будут медленными, и в вашем случае, вероятно, также необходимо сделать куски.

Ответ 5

select *
from table1  -- contains 100k rows
left join table2 -- contains 1M rows
on table1.id1=table2.id2 -- this would run for ~100G times 
                         -- unless they are cached on sql side
where table1.id between 1 and 100000 -- but this optimizes things (depends)

можно было бы превратить в

select id1 from table1 -- 400k bytes if id1 is 32 bit 
-- no need to order

сохранено в памяти

select id2 from table2 -- 4Mbytes if id2 is 32 bit
-- no need to order

хранится в памяти, оба массива отправляются в gpu с использованием ядра (cuda, opencl), как показано ниже

int i=get_global_id(0); // to select an id2, we need a thread id
int selectedID2=id2[i];
summary__=-1;
for(int j=0;j<id1Length;j++)
{
      int selectedID1=id1[j];
      summary__=(selectedID2==selectedID1?j:summary__); // no branching
}
summary[i]=j; // accumulates target indexings of 
"on table1.id1=table2.id2" part.

На стороне хоста вы можете сделать

 select * from table1 --- query3

и

 select * from table2 --- query4

затем используйте список id из gpu, чтобы выбрать данные

 // x is table1 ' s data
 myList.AsParallel().ForEach(x=>query3.leftjoindata=query4[summary[index]]);

Код gpu не должен быть медленнее, чем 50 мс для gpu с постоянной памятью, возможностью глобального вещания и несколькими тысячами ядер.

Если для фильтрации используется любая тригонометрическая функция, производительность будет быстро снижаться. Кроме того, когда слева объединенные таблицы подсчет строк делает сложностью O (m * n), то миллионы против миллионов будут намного медленнее. Здесь важна пропускная способность памяти GPU.

Edit: Единственная операция gpu.findIdToJoin(таблица1, таблица2, "id1", "id2" ) на моем hd7870 (1280 ядер) и R7-240 (320 ядер) с "таблицей продуктов (строки 64k)" и "таблица категорий ( 64k строк)" (фильтр левого соединения) занял 48 миллисекунд с неоптимизированным ядром.

Ado.Net "nosql" стиль linq-join занял более 2000 мс только с 44 тыс. продуктов и 4 тыс. категорий категорий.

Edit-2:

левое соединение с условием поиска строки получает от 50 до 200 x быстрее на gpu, когда таблицы вырастают до 1000 строк, каждый из которых имеет по меньшей мере сотни символов.