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();``
writeonly
C++里没有关键词(或
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`会提醒我们。
任何两个进行数据复制的容器都要在元素类型和元素数目上相匹配。如果两个容器都有秩(`array`到`array`、`array`到`array_view`、`array_view`到`array_view`,或者`array_view`到`array`),那么秩也必须匹配。我们可以使用支持迭代器的标准容器。
时间: 2024-10-31 01:00:36