【问题标题】:Multi-threading molecular simulations in C++C++ 中的多线程分子模拟
【发布时间】:2020-03-04 05:14:45
【问题描述】:

我正在用 C++ 开发一个分子动力学模拟代码,它基本上将原子位置和其他属性作为输入,并根据牛顿运动定律模拟它们的运动。核心算法使用所谓的 Velocity Verlet 方案,如下所示:

//  iterate through time (k=[1,#steps])
double Dt = 0.002; // time step
double Ttot = 1.0; // total time
double halfDt = Dt/2.0;

for (int k = 1; k*Dt <= Ttot; k++){
    for (int i = 0; i < number_particles; i++)
        vHalf[i] = p[i].velocity + F[i]*halfDt; // step 1

    for (int i = 0; i < number_particles; i++)
        p[i].position += vHalf[i]*Dt; // step 2

    for (int i = 0; i < number_particles; i++)
        F[i] = Force(p,i); // recalculate force on all particle i's

    for (int i = 0; i < number_particles; i++)
        p[i].velocity = vHalf[i] + F[i]*halfDt; // step 3
}

p 是一个类对象数组,用于存储粒子位置、速度、质量等信息,Force 是一个函数,它使用 Lennard-Jones 势等计算粒子上的净力。

我的问题是关于完成计算所需的时间;我所有的子程序都在处理数字方面进行了优化(例如,使用x*x*x 提高到三次方而不是pow(x,3)),但主要问题是时间循环通常会执行数百万次迭代,并且通常有接近一百万个粒子。有没有办法使用多线程来实现这个算法?根据我的理解,多线程本质上打开了另一个进出 CPU 内核的数据流,这将允许我同时运行两个不同的模拟;我想使用多线程来使其中一个模拟运行得更快

【问题讨论】:

  • 执行线程是程序的执行流程。当您有 1 个线程时,您的代码中有 1 个点是程序在给定时间所在的位置,即当前正在评估的函数或表达式。使用多线程,您有多个点,每个点同时运行。不是为多线程设计的代码不能轻易地与多线程一起安全使用。这不是你可以打开的东西。您需要转换您的代码,并且在执行此操作时很难不引入细微的更改或错误。
  • 多线程粒子模拟通常非常简单。您使用双缓冲数据并将所有粒子的处理划分为 N 个组,其中 N 是线程数。
  • 我想你需要当前时间步的完整结果才能开始下一个时间步。仅此一项就表明您不会从使用更多线程中获得最大收益。考虑将时间步重新表述为矩阵乘法,然后寻找并行矩阵乘法算法,应该有很多
  • Re,“多线程......打开另一个数据流......”不,这根本不对。您是否曾尝试通过思考计算机如何逐一执行程序语句来理解程序?好的,现在从你的脑海中抹去“计算机”并开始说“一个线程”。 thread 是操作系统中执行代码的实体,在多线程程序中,您有多个线程,所有线程都并行执行,可能执行不同的部分您的程序的...与否,在同一个共享地址空间中。
  • @SolomonSlow “一个接一个地执行程序语句”严格来说对于单个线程也是错误的。首先是因为现代 cpu 不会一个接一个地执行指令,还因为 cpu 不会执行用代码编写的程序语句,而是编译器从中产生的。虽然我正在分裂头发;)

标签: c++ multithreading


【解决方案1】:

我建议使用OpenMP

您的特定用例可以轻松并行化。 并行化应该很简单:

double Dt = 0.002; // time step
double Ttot = 1.0; // total time
double halfDt = Dt/2.0;

for (int k = 1; k*Dt <= Ttot; k++){

    #pragma omp parallel for
    for (int i = 0; i < number_particles; i++)
        vHalf[i] = p[i].velocity + F[i]*halfDt; // step 1
        p[i].position += vHalf[i]*Dt; // step 2

    #pragma omp parallel for
    for (int i = 0; i < number_particles; i++)
        F[i] = Force(p,i); // recalculate force on all particle i's    
        p[i].velocity = vHalf[i] + F[i]*halfDt; // step 3
}

大多数流行的编译器和平台都支持 OpenMP。

【讨论】:

  • number_particles 应该足够大以证明线程同步开销是合理的。否则你的加速可以是&lt; 1
  • 这最初是我认为多线程可以做的,即将一个核心专用于每个i for 循环。我发布问题的原因是该算法需要在每个时间步按顺序执行每个循环;您提出的方法是否仍然适用于我正在尝试做的事情?
  • @Iratium 这不会在不同的线程中运行每个。这会将每个 for 拆分为 N 个分区,并在不同的核心中运行每个分区。然后在for结束时加锁,直到所有分区都完成。它可以满足您的需求。
猜你喜欢
  • 1970-01-01
  • 2020-08-03
  • 1970-01-01
  • 2011-06-16
  • 2016-02-21
  • 2020-09-05
  • 2017-12-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多