0

我已经使用 parallel_for 实现了该算法。但大多数情况下我使用同步部分,所以我没有利润。也许有更好的选择?

    tbb::parallel_for (tbb::blocked_range<int>(1, m * n), apply_transform(d, j, this, m, n));

    void apply_transformation(int * d, int i, int j, int n){
        int elem1 = (*v1)[i];
        int elem2 = (*v2)[j];
        if(elem1 == elem2){
            dLock.acquire(dMutex);
            d[i*n + j] = d[(i-1)*n + j-1];       // no operation required
            dLock.release();
        } else {
            dLock.acquire(dMutex);
            d[i*n + j] = std::min(std::min(d[(i-1)*n + j] + 1, //deletion
                    d[i*n + j-1] + 1), //insertion
                    d[(i-1)*n + j-1] + 1); //substitution
            dLock.release();
        }
    }

    class apply_transform{
        int * array;
        int m_j;
        Levenstein * m_l;

        int m, n;
        public:
            apply_transform (int* a, int j, Levenstein * l, int width, int height):
                array(a), m_j(j), m_l(l), m(width), n(height) {}

            void operator()(const tbb::blocked_range<int>& r ) const {
                for (int i=r.begin(); i!=r.end(); i++ ){
                    m_l->apply_transformation(array, i, m_j, n);
                }
            }
    };
4

1 回答 1

5

Levenstein 距离计算本质上是一种波前模式,其中的计算d(i,j)需要了解d(i-1,j-1)d(i-1,j)d(i,j-1)。这些依赖关系自然形成了任务的 DAG;一个要计算的任务d(i,j)只有在其所有前任(以及它们的前任等)都完成后才能执行。已解决所有依赖关系且不相互依赖的任务(例如d(1,2)d(2,1))可以并行处理。除了遵循依赖关系,不需要其他同步。

有几种方法可以在 TBB 中表达波前模式:使用低级任务(复杂且不推荐),使用parallel_do原子计数器(如TBB 设计模式文档中所述;那里使用的示例与您所做的非常接近)并使用流程图(如TBB 博客中所述)。我建议您研究这些文档并进行自己的实验。

另请注意,计算单个的工作量d(i,j)太小,无法证明并行执行的开销是合理的。为了实现一些加速,将一个矩形计算块聚合到一个任务中,在任务中串行处理块元素。这些块将具有相同的依赖模式。但是您制作的块越大,可用的并行度就越少,因此您可能希望尝试使用块大小以获得最佳性能。

于 2012-12-19T21:22:28.977 回答