C ++多线程操作比单线程慢

时间:2018-03-15 15:56:53

标签: c++ multithreading

我在C ++的一个类中通过一维向量乘法执行3D矩阵。所有变量都包含在类中。当我在一个线程上创建一个类的实例并执行100次乘法时,乘法运算每次需要大约0.8ms。 当我创建4个类的实例,每个实例在一个单独的线程上,并在每个实例上运行25次乘法运算时,每次操作需要大约1.7ms。每个线程上的操作都是在单独的数据上执行的,并且在不同的核心上运行。 然而,正如预期的那样,完成100次矩阵乘法的总时间在单个线程上减少了4个线程。

我的问题是: 1)当使用多个线程时,乘法运算减速的原因是什么? 2)是否有任何方法可以加快操作?

编辑: 澄清问题: 当我将它们分成4个线程时,执行100个矩阵产品的总时间确实会减少 - 线程确实会使整个程序更快。 有问题的时间是已经创建的线程中的实际矩阵乘法(参见代码)。这次排除了线程创建和内存分配&删除。当我使用4个线程而不是1时,这是加倍的时间。当我使用4个线程时,执行所有乘法的总时间减半。我的问题是为什么单个矩阵产品在4个线程而不是1个线程上运行时速度较慢。

以下是代码示例。这不是我的实际代码,而是我编写的一个简化示例来演示问题。

Multiply.h

class Multiply
{
public:
  Multiply ();
  ~Multiply ();

  void
  DoProduct ();

private:
  double *a;
};

Multiply.cpp

Multiply::Multiply ()
{
  a = new double[100 * 100 * 100];
  std::memset(a,1,100*100*100*sizeof(double));
}

void
Multiply::DoProduct ()
{
  double *result = new double[100 * 100];
  double *b = new double[100];

  std::memset(result,0,100*100*sizeof(double));
  std::memset(b,1,100*sizeof(double));

  //Timer starts here, i.e. excluding memory allocation and thread creation and the rest
  auto start_time = std::chrono::high_resolution_clock::now ();

  //matrix product
  for (int i = 0; i < 100; ++i)
    for (int j = 0; j < 100; ++j)
    {
      double t = 0;

      for (int k = 0; k < 100; ++k)
    t = t + a[k + j * 100 + i * 100 * 100] * b[k];

      result[j + 100 * i] = result[j + 100 * i] + t;
    }

  //Timer stops here, i.e. before memory deletion

  int time = std::chrono::duration_cast < std::chrono::microseconds > (std::chrono::high_resolution_clock::now () - start_time).count ();

  std::cout << "Time: " << time << std::endl;

  delete []result;
  delete []b;
}

Multiply::~Multiply ()
{
  delete[] a;
}

Main.cpp的

void
threadWork (int iters)
{    
  Multiply *m = new Multiply ();

  for (int i = 0; i < iters; i++)
  {
    m->DoProduct ();
  }
}

void
main ()
{
  int numProducts = 100;
  int numThreads = 1; //4;
  std::thread t[numThreads];

  auto start_time = std::chrono::high_resolution_clock::now ();

  for (int i = 0; i < numThreads; i++)
    t[i] = std::thread (threadWork, numProducts / numThreads);

  for (int i = 0; i < n; i++)
    t[i].join ();

  int time = std::chrono::duration_cast < std::chrono::microseconds > (std::chrono::high_resolution_clock::now () - start_time).count ();

  std::cout << "Time total: " << time << std::endl;
}

1 个答案:

答案 0 :(得分:0)

与普通函数调用相比,异步和线程调用非常耗时。所以预启动线程并创建一个线程池。您将函数作为任务推送,并请求线程池从prority-queue中连接这些任务。

可以设置优先级,以便按正确顺序执行以避免使用,从而因使用互斥锁和锁而导致延迟

您正在启动太多线程,将其保持在系统允许的最大值以避免瓶颈。