zoukankan      html  css  js  c++  java
  • 蛙蛙推荐:F#实现并行排序算法

    摘要:F#是微软推出的一套函数式编程语言,能在CLR中运行,且和.NET其它语言能很好的交互,又因为它对并发编程的特殊支持,比如不变对象,异步表达式,新的并行基元等,所以很值得入门学习一下。现在我们综合应用这些技术写一个并行排序算法,并对其进行性能测试。

    思路:并行算法中其中有一种比较常见的方法就是先把要处理的数据分成若干份,然后让不同的线程(CPU)去处理,然后所有的线程处理完成后,把结果汇聚在一起,在一个独立的线程里完成结果合并,从而形成最终结果。在做分割的时候尽量让每个线程只访问自己独立的数据,而不访问全局数据和其它线程的数据(这里说的数据是非只读数据),在合并结果的时候要有一种高效的算法来合并。

    排序算法里有归并排序算法,我们先写一个多路归并排序算法,然后把要排序的数组分成CPU的个数份,让每个CPU去对每一份进行排序,所有线程排序完成后汇聚在一起,在一个独立的线程里进行归并排序。

    大概再解释一下代码,可能有些人对f#还不熟悉。
    1、归并算法的思路就是把多个已经排序的数组合并成一个大的排序数组,先从每个分数组的最小下标开始,谁都最小就放到大数组里,然后这个数组的下标加一,然后再比较,再把最小的放到大数组里,重复,直到所有的小数组的下标已经指向到末尾。其中会用到一个临时变量min,所以用mutable关键字修饰。
    2、F#的数组的长度用Array.length方法得出,变量和数组的赋值符号是<-,而不是=,=相当于c#里的==,f#里没有continue和break等关键字
    3、async关键字是一个新的并行基元,用它扩住的代码由f#自动的异步在线程池里执行,如果里面要返回结果的话,要用let!和return!关键字,我们的排序只是对数组进行操作,并不返回,所以这里比较简单。
    4、(fun a b -> a - b)是一个lamda表达式,它可以自动转换成Comparer<T>,起到排序依据的作用
    5、Array.map表示把一个数组里的每个元素应用一个方法,它这时候不执行,会通过管道传递给Async.Parallel方法,Async.Parallel方法返回一个异步执行数组Async<'a array>,最后用Async.Run来真正执行Async.Parallel返回的结果。
    6、|>表示管道的意思,大致就是把前一个函数的结果让后一个函数来用,这样一条语句可以表达很连贯的逻辑。

    整体代码如下:

     1 #light
     2 
     3 open System
     4 open System.Diagnostics
     5 open Microsoft.FSharp.Control.CommonExtensions
     6 
     7 let merge_sort destArray source cmp =
     8    let N = Array.length source
     9    let L = Array.length destArray - 1
    10    let posArr = Array.create N 0
    11    for i = 0 to L do
    12       let mutable min = -1
    13       for j = 0 to N - 1 do
    14          if posArr.[j] >= Array.length source.[j] then ()
    15          else
    16             if min = -1 then min <- j
    17             else
    18                if (cmp source.[j].[posArr.[j]] source.[min].[posArr.[min]]) < 0 then min <- j
    19       if min = -1 then ()
    20          else
    21             destArray.[i] <- source.[min].[posArr.[min]]                             
    22             posArr.[min] <- posArr.[min] + 1
    23 
    24 let parallel_sort cmp arr =
    25     let processorCount = Environment.ProcessorCount;
    26     let partArray = Array.create processorCount [||]
    27     let mutable remain = Array.length arr
    28     let partLen = Array.length arr / processorCount
    29 
    30     for i = 0 to processorCount - 1 do
    31         if i = processorCount - 1 then
    32             let temp_arr = Array.create remain 0
    33             Array.Copy(arr, i*partLen, temp_arr, 0, remain)
    34             partArray.[i] <- temp_arr
    35         else
    36             let temp_arr = Array.create partLen 0
    37             Array.Copy(arr, i*partLen, temp_arr, 0, partLen)
    38             remain <- remain - partLen
    39             partArray.[i] <- temp_arr
    40 
    41     let a_sort_one arr =
    42         async {
    43             Array.sort cmp arr
    44         }
    45         
    46     let a_sort_all =
    47         partArray
    48         |> Array.map (fun f -> a_sort_one f)
    49         |> Async.Parallel
    50         |> Async.Run
    51         
    52     a_sort_all
    53     let ret = Array.create (Array.length arr) 0
    54     merge_sort ret partArray (fun a b -> a - b)
    55     ret
    56 
    57 let arr = Array.create 1000000 0
    58 let rnd = new Random()
    59 for i = 0 to Array.length arr - 1 do
    60     arr.[i] <- rnd.Next()
    61 
    62 let stop = Stopwatch.StartNew()
    63 stop.Start
    64 let sorted_arr = parallel_sort (fun a b -> a-b) arr
    65 stop.Stop
    66 printfn "并行排序结果\r\n=%A\r\n用时%d毫秒" sorted_arr stop.ElapsedMilliseconds          
    67 
    68 let stop2 = Stopwatch.StartNew()
    69 Array.sort (fun a b -> a-b) arr
    70 stop.Stop
    71 printfn "串行排序结果\r\n=%A\r\n用时%d毫秒" arr stop2.ElapsedMilliseconds   
    72 
    73 Console.ReadKey(true)   


    我本机,IBM X200测试串行排序大约在1200多秒,并行排序在900秒左右。

    相关链接:
    从简单的 F# 表达式构建并发应用程序
    http://msdn.microsoft.com/zh-cn/magazine/cc967279.aspx
    从C# 3.0到F#
    http://www.cnblogs.com/allenlooplee/archive/2008/07/25/1251631.html
    F#系列随笔索引
    http://www.cnblogs.com/anderslly/archive/2008/10/08/fs-posts-indices.html
    Concurrency with MPI in .NET
    http://weblogs.asp.net/podwysocki/archive/2008/05/15/concurrency-with-mpi-in-net.aspx
    使用 .NET Framework 中的函数式编程技术
    http://msdn.microsoft.com/zh-cn/magazine/cc164244.aspx
  • 相关阅读:
    URAL 1998 The old Padawan 二分
    URAL 1997 Those are not the droids you're looking for 二分图最大匹配
    URAL 1995 Illegal spices 贪心构造
    URAL 1993 This cheeseburger you don't need 模拟题
    URAL 1992 CVS
    URAL 1991 The battle near the swamp 水题
    Codeforces Beta Round #92 (Div. 1 Only) A. Prime Permutation 暴力
    Codeforces Beta Round #7 D. Palindrome Degree hash
    Codeforces Beta Round #7 C. Line Exgcd
    Codeforces Beta Round #7 B. Memory Manager 模拟题
  • 原文地址:https://www.cnblogs.com/onlytiancai/p/fsharp_sort.html
Copyright © 2011-2022 走看看