《C++ AMP:用Visual C++加速大规模并行计算》——3.8 在CPU和GPU之间复制数据

本节书摘来自异步社区出版社《C++ AMP:用Visual C++加速大规模并行计算》一书中的第3章,第3.8节,作者: 【美】Kate Gregory , Ade Miller,更多章节内容可以访问云栖社区“异步社区”公众号查看。

3.8 在CPU和GPU之间复制数据

C++ AMP:用Visual C++加速大规模并行计算
数据可以在CPU和加速器(通常是GPU)之间自动复制,也可以根据需要使用amp.h中众多的copy()重载函数之一显式复制。例如,我们可以在默认加速器上构造array,然后仅使用一条函数调用便可以把数据复制进去:

array<int, 1> a(5, v.begin(), v.end());
此外,我们还可以构造空数组,然后再使用copy()函数来加载数据。array_view在CPU上有一个对应容器,当加速器上的array_view开始处理时,array_view会自动把数据复制到加速器里,并把发生变化的数据同步回去在CPU上使用,如3.5节所述。

这两段代码段是等价的:

std::vector<int> v(5);                std::vector<int> v(5);
std::iota(v.begin(), v.end(), 0);          std::iota(v.begin(), v.end(), 0);
array<int,1> a(5,v.begin(),v.end());        array_view<int,1> av(5,v);
parallel_for_each(a.extent, [&](index<1> idx)   parallel_for_each(av.extent, [=]                                 (index<1> idx)
  restrict(amp)                      restrict(amp) 
{                             {
  a[idx] = a[idx] * 2;                  av[idx] = av[idx] * 2;
});                            });  
copy(a,v);                        av.synchronize();```
如果要在`parallel_for_each`之后访问CPU上的`array_view`,它将自动同步,因此我们可以忽略这条调用。这是使用`array_view`最大的优势所在。

当然,自动复制如非真正需要便会造成性能受损。C++ AMP让我们可以真正控制自动复制。在声明`array_view`的时候,我们可以给编译器一个暗示,说明数据将要发送到加速器上,但不会在那里改变:

`array_view<const int, 1> a(5, v);`
这么做会防止自动将加速器数据复制返回。这种聪明的关键词和概念复用方法,已为C++开发者所熟知。我们还可以暗示无需把初始值复制到加速器里,因为核函数会重写这些初始值,例如:

array_view out(5, v2);
out.discard_data();`
C++里没有writeonly关键词(或anti_const),因此我们要代而使用这种函数调用。

还有一种方法可以从array_view中取出数据并返还给它所包装的CPU集合,以便array_view作析构之用。例如,这种代码即使在没有调用synchronize的情况下,也可以让计算结果出现在std::vector v2中:

std::vector<int> v(5), v2(5, 0);
std::iota(v.begin(), v.end(), 0);
// braces for scope only
{
  array_view<const int, 1> a(5, v);
  array_view<int, 1> out(5, v2);
  out.discard_data();
  parallel_for_each(a.extent, [=](index<1> idx) restrict(amp)
  {
    out[idx] = a[idx] * 2;
  });
}```
对于数组视图来说,作用域结束的时候就会自动执行复制,这时const暗示的重要性就凸显出来了,因为我们不需要把没有改变的值从a复制回v,而暗示会阻止这种操作的发生。

任何时候,我们都可以显式地从一个数组把数据复制到另一个数组,或者从一个array_view把数据复制到另一个,或者从一个数组复制到std::vector等位于CPU的集合中。复制的两个参数分别是源和地址。

注意事项:
受限于对标准库方法的掌握程度,我们会发现要想记住参数顺序并非很容易,标准库方法大多以源作为第一个参数,而C风格函数一般会把目标作为第一个参数。但是,我们必须要选择一个参数顺序,它可能更像是标准库而不像C。C++ AMP的设计师一般要遵循C++约定,而非C约定。如果需要提示,`IntelliSense`会提醒我们。
上一篇:重庆规模最大数据中心启用


下一篇:若5G的速度不够:那6G和16K是必然么?