cod*_*nk1 2 queue performance ocaml functional-programming
我注意到queue.ml由于其基于链表的实现(具有可变字段)而趋于相当慢
是否可以构建具有更快结构的队列,例如数组?
或者有没有办法实现更好的表现,但仍然是功能性的方式?
编辑:我想实现一个发布 - 订阅解决方案,成千上万的人在不到一毫秒的时间内排队并提供操作(对于图形交互式应用程序),所以我需要一些非常快的东西并且ocaml队列实现没有满足我的性能需求
知道为什么你认为基于链表的实现很慢会很有趣.这是队列的经典实现.插入和删除速度与我想象的一样快(更新一个或两个参考字段).请注意,我没有查看您正在谈论的代码.
您可以使用数组实现环形缓冲区.某些事情可能会更快(比如遍历所有元素),但会有最大的大小(对于最简单的实现).初始化阵列也有复杂性.
一般而言,数据结构的功能(不可变)实现比相应的命令式(可变)版本慢一点.有一个非常好的功能队列实现,具有很好的性能.基本技巧是将队列的一半保持在正向顺序(快速删除),将一半保持在相反的顺序(快速插入).逆转的额外传球引入了一个小的惩罚,就像我说的那样.
如果您正在查看内存(分配和GC),则不可变方法将分配最多,经典方法为中等量,而环形缓冲区将分配很少.但是一个好的FP实现(比如OCaml)可以非常快速地分配内存,如果对象是短暂的,那么回收它也不会太慢.
编辑:为了它的价值,我只是在我的笔记本电脑(3.06 GHz英特尔酷睿2双核处理器)上进行了非常粗略的定时测试,我可以使用70毫秒的标准OCaml队列模块将一百万个值排队并出列.那么大约需要.7毫秒来做10,000(如果我做对了).如果你的CPU不比我的快,那么做你想要的东西似乎不够快.
编辑2:我只是手写了一些代码,假设你的值中有一个预先存在的引用字段,可用于排队.这避免了在排队代码中进行任何分配,但在其他方面类似于标准的Queue模块(尽管不那么优雅).在与上面相同的笔记本电脑上,一百万个队列和出列需要大约48毫秒.所以它快一点.
编辑3:很可能你现在已经得到了你的答案,但我只是使用上面概述的纯队列实现进行了粗略的计时测试,我看到大约18毫秒来做一百万个队列并且出列.所以它的速度要快得多.这是合理的,因为OCaml针对纯计算进行了调整.这是我的代码; 你可以检查是否有任何错误.
type q = {
head: int list;
tail: int list;
}
let q_add q i =
{ q with tail = i :: q.tail }
let q_take q =
match q.head with
| [] ->
begin
match List.rev q.tail with
| [] -> raise Not_found
| h :: t -> (h, { head = t; tail = [] })
end
| h :: t -> (h, { head = t; tail = q.tail })
let main () =
let q = q_add { head = []; tail = [] } 0
in let now = Unix.gettimeofday ()
in let rec go q i =
if i > 1_000_000 then
q
else
let (_, q') = q_take (q_add q i)
in
go q' (i + 1)
in let _ = go q 1
in let duration = Unix.gettimeofday () -. now
in
Printf.printf "%f\n" duration
let () = main ()
Run Code Online (Sandbox Code Playgroud)
就像我说的,这是一个粗略的考验.队列的长度仅为1到2个元素.我不确定结果会在您的环境中保持不变.但它很有趣.