我正在编写一个使用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)有没有办法优化我的代码以加快速度?
答案 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的提交历史记录应包含其他失败尝试的记录。