14.1.1 命令式代码的并行化

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

14.1.1 命令式代码的并行化

在命令式编程中,for 循环可能是很容易并行化的最常见结构。循环的迭代器独立(independent)时,就可以在单独的线程上执行。就是说,由于独立,迭代器不会依赖前面任何迭代器所计算的值。
例如,统计数组中元素时,要计算下一个元素,就需要统计前面元素的总和。(这仍可以并行,但是不那么简单。)回想一下我们在第十章实现的“模糊”数组的函数,非常适合并行化:虽然每次迭代使用输入数组的多个元素,但它不依赖输出数组中的任何元素。清单 14.1 显示了基于前面示例的简单 for 循环,包含 C# 和 F# 两个版本。

清单14.1 用 for 循环计算模糊数组 (C# and F#)

C#  F#
for(int i=1; i<inp.Length-1; i++){ 
  var sum = inp[i-1] + 
    inp[i] + inp[i+1]; 
  res[i] = sum / 3; 
}   for i in 1 .. inp.Length - 2 do 
  let sum = inp.[i-1] +
             inp.[i] + inp.[i+1] 
  res.[i] <- sum / 3

虽然这是命令式代码,但仍可以成为纯函数式程序的一部分。Inp 是输入数组,在代码中的所有地方都不能修改,res 是输出数组,在循环计算后,也不应该进行修改。
要将循环并行化,可以使用 Parallel.For 方法。这个类在命名空间 System.Threading.Tasks 下,只在 .NET 4.0 上才可用。Parallel.For 方法的参数为 Action 委托值,可以由 lambda 函数提供。F# 中,直接使用这个方法感觉有点大材小用,所以,我们会定义一个简单的函数,使代码更简洁:

let pfor nfrom nto f = 
  Parallel.For(nfrom, nto + 1, Action<_>(f)) |> ignore

这段代码把函数 f (其类型为 int -> unit)包装在委托类型,运行并行的 for 循环。方法返回循环是否成功完成的信息,但我们并不需要,所以就忽略了。注意,我们还在上限上加了 1,因为在 F# 的 for 循环是包容上限的,而在 C# for 循环和 Parallel.For 方法中是不包含上限的。清单 14.2 显示前面示例的并行化版本。

清单14.2 并行折 for 循环 (C# and F#)
C# F#

Parallel.For(1,inp.Length-1,i => { 
  var sum = inp[i-1] + 
    inp[i] + inp[i+1]; 
  res[i] = sum / 3; 
}); pfor 1 (inp.Length-2) (fun i –> 
  let sum = inp.[i-1] + 
            inp.[i] + inp.[i+1] 
  res.[i] <- sum / 3 
)

可以发现,这与原始的串行版本几乎一样简单。另外,还表明了函数式构造的强大:由于有 lambda 函数,把串行的 for 循环转换为并行时,唯一要做的是使用 Parallel.For 方法(或在 F# 中使用 pfor 函数),代替内置的语言构造。

注意

在 Parallel 类中,除了有 For 方法,还有 ForEach 方法,可用于对 C# 中的 foreach 构造,或 F# 中的 for …in … do 构造进行并行化。这两个方法都可以重载,自定义迭代器。重载可以改变步长,增加 For 方法中的索引,或者停止并行执行(类似于 C# 中的循环中断break)。如果觉得需要更多一点儿控制,就请参考文档,看看其中是否有重载可以帮助你。

处理数组和其他命令式数据结构,Parallel.For 方法特别有用。在这一章的后面(第 14.2.5 节),我们会在更大的示例应用程序中再次用它来以函数方式处理数组。现在,就先结束介绍,下面要讨论的两种技术都是纯函数式的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值