14.3.5 以并行方式运行仿真

728 篇文章 1 订阅
26 篇文章 0 订阅

14.3.5 以并行方式运行仿真

 

    要并行运行模拟,我们将使用 Task 基于任务的并行度,和使用 PLINQ (和 F# 中的 PSeq 模块)声明式并行度的组合。计算仿真的新状态,需要执行两个基本任务:移动所有动物,移动所有捕食者。有了 14.3.4 节的算法,这两个任务花大致相同的时间,所以,这在一代上双核的机器上就足够了。

    把这个工作拆分为两个任务,并不是最好的选择,如果我们有一台机器有两个以上的处理器,或者如果这些任务中的一个比其他的花的时间更长。在这里,我们可以使用声明性数据并行度,因为,我们可以独立计算每个动物和捕食者的新的位置:我们可以把它看作一个列表处理操作。清单 14.27 使用这两种技术来实现一个 F# 函数,运行仿真。

 

Listing 14.27 Generating random state and running a simulation step (F#)

 

let simulationStep(state) =
  let futureAnimals = Task.Factory.StartNew(fun () –>
    state.Animals
      |> PSeq.ofSeq
      |> PSeq.map (moveAnimal state)
      |> List.ofSeq)
  let predators =
    state.Predators
      |> PSeq.ofSeq
      |> PSeq.map (movePredator state)
      |> List.ofSeq
  { Animals = futureAnimals.Result; Predators = predators }

type Simulation with
  member x.Step() = simulationStep(x)
  static member CreateInitialState() =
    { Animals = randomLocations(150) |> List.ofSeq
      Predators = randomLocations(15) |> List.ofSeq }

 

    这个清单把这个仿真步骤实现为 F# 函数,使用类型扩展,使此函数成为 Simulation 类型的一部分,它添加了 CreateInitialState 方法,生成 150 个随机位置的动物和 15 个随机位置的捕食者。

    仿真步骤在背景中,使用 Task,启动处理动物的集合,然后,在当前线程上处理捕食者,所以,我们只需要一个 Task 值。这类似于我们前面讨论过的树处理代码。每个任务创建一个新列表,下一个步骤的位置。列表处理使用 PSeq 模块进一步并行化。

 

提示

 

    调整代码以获得最大性能,总是很困难的,需要大量的实验。如果你运行有两种并行化技术有仿真,应该有助理的加速。对双核心机器上,是当我们只使用 Task 顺序实现的速度约 155% ,使用 PLINQ 和 Task 时的速度的 175%。可以尝试使用不同的配置,以找到在你的系统上的最佳性能。

 

    Step 方法的 C# 实现是类似于 F# 版本,如你在下面看到的。

 

Listing 14.28 Running the simulation step in parallel (C#)

 

public Simulation Step() {
  var futureAnimals = Task.Factory.StartNew(() =>
    Animals.AsParallel()
      .Select(a => MoveAnimal(a))
      .ToList());
  var predators =
    Predators.AsParallel()
      .Select(p => MovePredator(p))
      .ToList();
  return new Simulation(futureAnimals.Result, predators);
}

 

    就像在 F# 版本中一样,我们创建一个 Task 值处理动物,运行这个代码,在主线程上处理捕食者。每个列表处理任务使用 AsParallel 方法,所以,查询运算符并行执行。我们只需要 Select 运算符,为每个动物或捕食者得到一个新的位置,直接使用扩展方法,而不是写查询表达式。最后,我们创建一个新的 Simulation 对象,保存新的状态。

    正如你可以看到的,以并行方式运行仿真,并不困难,因为在应用程序设计中,我们使用了函数技术。表示状态的数据结构是不可变的,在仿真中的每一步骤中,我们创建了一个新状态。这意味着,在多个线程中并发运行,更新状态,不会遭遇竞争。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值