比较F#中两个字节数组的最快方法

时间:2014-10-28 10:04:24

标签: f# kinect

我正在编写一个使用Kinect照片数据的应用程序,并在F#中将两个帧相互比较。我正在使用Rob Miles 了解Kinect Api 第74页作为指南,但我没有使用指针而且性能正在受到影响。 Kinect帧的字节为1,228,800字节。我写了这样的比较:

member this.differenceCount(currentImageBytes) =
    if  previousImageBytes |> Seq.length = 0 then
        previousImageBytes <- currentImageBytes
        0
    else
        let bytes = Seq.zip previousImageBytes currentImageBytes
        let differenceCount = bytes |> Seq.mapi(fun i e -> i, e)
                                    |> Seq.filter(fun (i,e) -> i % 4 <> 0 )
                                    |> Seq.map snd
                                    |> Seq.filter(fun (p,c) -> p <> c)
                                    |> Seq.length
        previousImageBytes <- currentImageBytes
        differenceCount

当我运行它时,屏幕滞后,因为(我认为)处理数组花费的时间太长。此外,错误率接近50%。

1)我接近问题了吗? 2)有没有办法优化我的代码以加快速度?

3 个答案:

答案 0 :(得分:10)

通过元组进行序列映射/过滤会导致很多拳击开销。以下示例避免了装箱并且并行工作,这在我的机器上快了50倍。

let parallelRanges =
    let kinectSize = 1228800
    let subSize = kinectSize / Environment.ProcessorCount
    let iMax = kinectSize - 1
    let steps = [| -1 .. subSize .. iMax |]
    steps.[steps.Length - 1] <- iMax
    steps |> Seq.pairwise |> Seq.toArray |> Array.map (fun (x, y) -> x + 1, y)

let countDiffs (prevBytes:byte[]) (curBytes:_[]) =
    let count (fromI, toI) =
        let rec aux i acc =
            if i > toI then acc
            elif i % 4 <> 0 && prevBytes.[i] <> curBytes.[i] then 
                aux (i + 1) (acc + 1)
            else aux (i + 1) acc
        aux fromI 0

    parallelRanges
    |> Array.Parallel.map count
    |> Array.sum

答案 1 :(得分:3)

如果没有一些测试数据来分析和比较,我会做类似

的事情
let len = Array.length previousImageBytes
let mutable count = 0
for i in 0 .. 4 .. (len-1) do
    if previousImageBytes.[i] <> currentImageBytes.[i] then
        count <- count+1

对数据进行一次传递而不是5次,并避免seq函数缓慢。

答案 2 :(得分:1)

对于我正在研究的项目,我已经在F#中尝试了几种不同的字节数组比较实现。

从广义上讲,对于这个特殊问题,我发现&#34;更为惯用的F#&#34; ==&#34;慢&#34;。所以我最终得到了这个:

// this code is very non-F#-ish.  but it's much faster than the
// idiomatic version which preceded it.

let Compare (x:byte[]) (y:byte[]) =
    let xlen = x.Length
    let ylen = y.Length
    let len = if xlen<ylen then xlen else ylen
    let mutable i = 0
    let mutable result = 0
    while i<len do
        let c = (int (x.[i])) - int (y.[i])
        if c <> 0 then
            i <- len+1 // breaks out of the loop, and signals that result is valid
            result <- c
        else
            i <- i + 1
    if i>len then result else (xlen - ylen)

我违反了好的功能编程指南。我使用了if-then-else而不是匹配。我有变数。我伪造了一个break语句,对循环索引变量做了一个俗气的改变。

然而,这最终比任何更惯用的东西快得多。甚至像尾部递归的闭包这样简单的东西也比较慢。 (分析器指示闭包涉及堆上的内存分配。)

包含此代码的项目位于GitHub:

https://github.com/ericsink/LSM

fs / lsm.fs的提交历史记录应包含其他失败尝试的记录。