是否可以使用GPU加速(动态)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那样,但你得到的想法)和/或返回实际数据。

只是总结一下我/我们需要的东西:

一种数据库,能够在不到100毫秒的时间内对200列和大约250 000行的数据进行排序。

我目前有一个带有并行化LINQ的解决方案,它能够(在特定的机器上)在过滤处理结果时每行只花费纳秒时间!

因此,我们需要在每一行上进行亚纳秒级过滤。

  1. 为什么只有内存LINQ能够提供这个?
  2. 为什么这不可能?

日志文件中的一些数字:

 Total tid för 1164 frågor: 2579 

这是瑞典语并翻译:

 Total time for 1164 queries: 2579 

这种情况下的查询是这样的查询:

 WHERE SomeProperty = SomeValue 

这些查询都是在225639行上并行完成的。

因此,225639行在大约2.5秒内在存储器中被过滤1164次。

这是9,5185952917007032597107300413827e-9秒/行, 但是 ,还包括数字的实际处理! 我们做Count(非null),总计数,Sum,Min,Max,Avg,Median。 因此,我们对这些过滤的行进行了7次操作。

所以,我们可以说它实际上比我们尝试过的数据库快7倍 ,因为在这些情况下我们不做任何聚合事情!

总而言之,与内存LINQ过滤相比,为什么数据库在过滤数据方面如此差劲? 微软真的做得这么好,以至于无法与它竞争吗? 🙂

尽管内存中过滤应该更快,但我不想要它更快。 我想知道什么是更快,如果可能的原因

我将最终回答有关Brahma的问题,因为它是我的图书馆,但它也可能适用于其他方法。 GPU不了解对象。 它的内存也大部分与CPU内存完全分开。

如果您确实拥有大量对象并希望对其进行操作,则只能将要操作的数据打包到适合您正在使用的GPU / API的缓冲区中,然后将其发送以进行处理。

请注意,这将在CPU-GPU内存接口上进行两次往返,因此如果您在GPU上做的工作不足以使其值得,那么您将比首先使用CPU时慢(像上面的样本)。

希望这可以帮助。

GPU实际上不是用于所有通用计算目的,特别是对于这样的面向对象设计,过滤任意数据集合这样的实际上并不合适。

GPU计算非常适合在大型数据集上执行相同操作的事情 – 这就是矩阵运算和变换等事情非常好的原因。 在那里,GPU上令人难以置信的快速计算能力可以超越数据复制….

在这种情况下,您必须将所有数据复制到GPU中才能使其工作,并将其重组为GPU将理解的某种forms,这可能比仅仅在软件中执行filter更昂贵。

相反,我建议使用PLINQ来加速这种性质的查询。 如果您的filter是线程安全的(它必须与任何GPU相关的工作……)这可能是通用查询优化的更好选择,因为它不需要内存复制您的数据。 PLINQ可以通过重写您的查询来工作:

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

如果谓词是一个昂贵的操作,或者集合非常大(并且易于分区),那么与标准的LINQ to Objects相比,这可以显着提高整体性能。

GpuLinq

GpuLinq的主要任务是通过LINQ实现GPGPU编程的民主化。 主要思想是我们将查询表示为表达式树,并在各种转换优化之后将其编译为快速OpenCL内核代码。 此外,我们提供了一个非常容易工作的API,而无需弄乱OpenCL API的细节。

https://github.com/nessos/GpuLinq

 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 

存储在内存中,两个数组都使用如下所示的内核(cuda,opencl)发送到gpu

 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 

在主机方面,你可以做

  select * from table1 --- query3 

  select * from table2 --- query4 

然后使用来自gpu的id​​列表来选择数据

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

对于具有恒定内存,全局广播能力和数千个内核的gpu,gpu代码不应低于50ms。

如果使用任何三角函数进行过滤,性能将快速下降。 此外,当左表连接表时,行数会使O(m * n)的复杂度降低,因此数百万对数百万的速度要慢得多。 GPU内存带宽在这里很重要。

编辑:我的hd7870(1280核)和R7-240(320核)上的“产品表(64k行)”和“类别”的gpu.findIdToJoin(table1,table2,“id1”,“id2”)的单个操作table(64k rows)“(左连接filter)使用未经优化的内核需要48毫秒。

Ado.Net的“nosql”风格linq-join花费超过2000毫秒,只有44k产品和4k类别表。

编辑-2:

当表增长到1000行,每行至少有数百个字符时,使用字符串搜索条件的左连接在gpu上快50到200倍。

你的用例的简单答案是否定的。

1)即使在原始的linq到对象中,也没有针对这种工作负载的解决方案,更不用说替代数据库了。

2)即使您一次性加载整个数据集(这需要时间),它仍然会慢得多,因为GPU具有高通过率,但是它们的访问是高延迟的,所以如果你看起来“非常”快解决方案GPGPU通常不是答案,因为只是准备/发送工作负载并且返回结果会很慢,在您的情况下可能也需要以块的forms完成。