许多排序向量与固定数量的线程的并行交集

时间:2015-05-24 16:57:29

标签: c++ multithreading algorithm c++11

我有以下排序的载体:

vector<unsigned> vector1;
vector<unsigned> vector2;
vector<unsigned> vector3;
...
vector<unsigned> vector30000;

我需要执行vector1与其余向量的交集。即我需要执行以下交叉点:

vectori1=intersection of vector1 with vector2;
vectori2=intersection of vector1 with vector3;
vectori3=intersection of vector1 with vector4;
...
vectori30000=intersection of vector1 with vector30000;

现在我需要找出所有非空向量的vectori1,vectori2,vectori3,...,vectori30000并将它们存储在“相交的”向量中。

为了做到这一点,我编写了以下序列化代码:

int main()
{
    vector<unsigned> vector1;
    vector1.push_back(10); vector1.push_back(20); vector1.push_back(30);
    vector<vector<unsigned> > vecOfVectors;
    vector<unsigned> vector2;
    vector2.push_back(1); vector2.push_back(5); vector2.push_back(8); vector2.push_back(10);
    vecOfVectors.push_back(vector2);
    vector<unsigned> vector3;
    vector3.push_back(3); vector3.push_back(20); vector3.push_back(25);
    vecOfVectors.push_back(vector3);
    vector<unsigned> vector4;
    vector4.push_back(28); vector4.push_back(29); vector4.push_back(39);
    vecOfVectors.push_back(vector4);
    vector<vector<unsigned> > intersected;
    for(vector<vector<unsigned> >::iterator it=vecOfVectors.begin(),l=vecOfVectors.end();it!=l;++it)
    {
        vector<unsigned> intersectedLocal;
        std::set_intersection(vector1.begin(),vector1.end,(*it).begin(),(*it).end(),back_inserter(intersectedLocal));
        if(!intersectedLocal.empty())
            intersected.push_back(intersectedLocal);
    }
}

为了提高性能,我需要并行化交集算法。我没有得到如何做同样的事情。我的尝试如下所示:

void multThreadIntersect(vector<unsigned>& vector1, vector<vector<unsigned> >::iterator it, int size,int i,vector<vector<unsigned> >& intersected,vector<int>& idIntersected)
{
    if(i<size) 
    {        
        vector<unsigned> intersectedLocal;
        std::set_intersection(vector1.begin(),vector1.end,(*it).begin(),(*it).end(),back_inserter(intersectedLocal));
        it++;
        idIntersected.push_back(i);
        intersected.push_back(intersectedLocal);
        auto future = std::async(std::launch::async,multThreadIntersect, vector1, it, size,intersected,idIntersected);
        future.wait();
        i++;
    }
    else
    {
        return;        
    }
}

int main()
{
    vector<unsigned> vector1;
    vector1.push_back(10); vector1.push_back(20); vector1.push_back(30);
    vector<vector<unsigned> > vecOfVectors;
    vector<unsigned> vector2;
    vector2.push_back(1); vector2.push_back(5); vector2.push_back(8); vector2.push_back(10);
    vecOfVectors.push_back(vector2);
    vector<unsigned> vector3;
    vector3.push_back(3); vector3.push_back(20); vector3.push_back(25);
    vecOfVectors.push_back(vector3);
    vector<unsigned> vector4;
    vector4.push_back(28); vector4.push_back(29); vector4.push_back(39);
    vecOfVectors.push_back(vector4);
    vector<vector<unsigned> >::iterator it=vecOfVectors.begin();
    int size=vecOfVectors.size();
    int i=0;
    vector<vector<unsigned> > intersected;
    vector<int> idIntersected; //contains those i's whose intersection was non-zero
    long unsigned int nThreads = std::thread::hardware_concurrency();
    multThreadIntersect(vector1,it,size,i,intersected,idIntersected);    
    cout<<"id intersected vector:";
    for(vector<int>::iterator it=idIntersected.begin(),l=idIntersected.end();it!=l;++it)
        cout<<" "<<(*it);
    cout<<"\n";
}

我使用的gcc版本是: gcc(GCC)4.8.2 20140120(Red Hat 4.8.2-15)

我已经在我的程序中定义了_GLIBCXX_PARALLEL。但是,由于vector1与vector2,...,vector30000的交集是相互独立的。因此,我正在考虑将vector1与vector2,vector1与vector3和vector1与vector30000并行交叉

2 个答案:

答案 0 :(得分:2)

您可以使用OpenMP来并行它:

omp_set_num_threads(2); // here set number of threads, if not set it defaults to number of the cores in the machine

#pragma omp parallel for
for (int x = 0; x < vecOfVectors.size(); ++x)
{
    vector<unsigned> intersectedLocal;
    std::set_intersection(vector1.begin(), vector1.end(), vecOfVectors[x].begin(), vecOfVectors[x].end(), back_inserter(intersectedLocal));
    if (!intersectedLocal.empty())
    {
        #pragma omp critical // execute one thread at a time
        intersected.push_back(intersectedLocal);
    }
}

启用OpenMP添加到链接器:-fopenmp

答案 1 :(得分:1)

有许多库/工具可以实现线程池。微软的人才,英特尔的tbb,OpenMP(根据我的经验,从易用性的降序排列)。如果有可用的话,请使用其中一个。

这是一个质量交叉函数。

它使用async。它可以透明地转换为使用线程池,方法是将调用替换为async,并传入线程池,或者调用由线程池支持的全局函数(取决于您使用的库):

std::vector<std::vector<unsigned>>
mass_intersect(
  std::vector<unsigned> filter,
  std::initializer_list< std::reference_wrapper<std::vector<unsigned> const> > targets
) {
  std::vector< std::future< std::vector<unsigned>>> working;
  working.reserve(targets.size());
  for (auto const& rhs:targets) {
    working.push_back( std::async( std::launch::async, [&rhs,&filter]{
      std::vector<unsigned> result;
      // do filter on rhs.get() and filter into result
      return result;
    });
  }
  // convert the above futures into a return value:
  std::vector< std::vector<unsigned>> retval;
  retval.reserve(working.size());
  for (auto&& r_f:working) {
    auto r = r_f.get(); // block
    if (r.empty()) continue;
    retval.push_back(std::move(r));
  }
  return retval;
}

我离开了实际的交叉点代码未完成。

它将vector s作为const向量的引用包。您可以使用以下方法构建它:

{ std::ref( v1 ), std::ref( v2 ), std::ref(v3) }

但实际上,它所需要的只是一个可迭代的源向量集合。

这是一个质量交叉函数

它使用async。它可以透明地转换为使用线程池,方法是将调用替换为async,并将线程池传递给:

std::vector<std::vector<unsigned>>
mass_intersect(
  std::vector<unsigned> filter,
  std::initializer_list< std::reference_wrapper<std::vector<unsigned> const> > targets
) {
  std::vector< std::future< std::vector<unsigned>>> working;
  working.reserve(targets.size());
  for (auto const& rhs:targets) {
    working.push_back( std::async( std::launch::async, [&rhs,&filter]{
      std::vector<unsigned> result;
      // do filter on rhs.get() and filter into result
      return result;
    });
  }
  // convert the above futures into a return value:
  std::vector< std::vector<unsigned>> retval;
  retval.reserve(working.size());
  for (auto&& r_f:working) {
    auto r = r_f.get(); // block
    if (r.empty()) continue;
    retval.push_back(std::move(r));
  }
  return retval;
}

我离开了实际的交叉点代码未完成。

它将vector s作为const向量的引用包。您可以使用以下方法构建它:

{ std::ref( v1 ), std::ref( v2 ), std::ref(v3) }

但实际上,它所需要的只是一个可迭代的源向量集合。

现在,大多数现有线程池不会与std::future和C ++ 11同步原语无关地进行交互(除了其他原因,因为它们先于它)。因此,除非您编写自己的线程池,否则必须进行一些调整。

如果你想编写一个线程池,这里有一个简短的草图一个线程池可以写一个条件变量,mutex(或shared_timed_mutex)和一个{{1的向量}}第

它维护一组线程,从promised_task队列中弹出任务。

添加任务时,界面看起来很像promised_task。界面草图:

async

我最近在另一个堆栈溢出答案中写了sketch of an implementation。以上只支持一次添加工作线程1:上面的界面允许您一次添加任意数量的线程。改变这很容易。它也只支持struct thread_pool { template<class F> std::future<std::result_of_t<std::decay_t<F>()>> queue(F&&f); std::future<void> abort(); // empties queue, kills all threads size_t thread_count() const; void add_threads(size_t n=1); ~thread_pool(); thread_pool(); thread_pool(thread_pool&&)=delete; thread_pool& operator=(thread_pool&&)=delete; private: // stuff }; 返回类型 - 再次,应该很容易修复。