Ocaml表现vs去

Sen*_*eca 0 performance ocaml go

我正在尝试在Ocaml中实现utf8解码作为学习项目.为了检查性能,我正在针对go标准库进行基准测试.

这是go代码:

package main

import (
    "fmt"
    "time"
    "unicode/utf8"
)

func main() {
    start := time.Now()

    for i := 0; i < 1000000000; i++ {
        utf8.ValidRune(23450)
    }

    elapsed := time.Since(start)
    fmt.Println(elapsed)
}
Run Code Online (Sandbox Code Playgroud)

当我运行它时,我得到:

go build b.go
./b
344.979492ms
Run Code Online (Sandbox Code Playgroud)

我决定在ocaml中写一个等价物:

let min = 0x0000
let max = 0x10FFFF

let surrogateMin = 0xD800
let surrogateMax = 0xDFFF

let validUchar c =
  if (0 <= c && c < surrogateMin) then
    true
  else if (surrogateMax < c && c <= max) then
    true
  else
    false

let time f x =
    let t = Sys.time () in
    let _ = f x in
    let t2 = Sys.time () in
    let diff = (t2 -. t) *. 1000. in
    print_endline ((string_of_float diff) ^ "ms")


let test () =
  for i = 0 to 1000000000 do
    let _ = validUchar 23450 in
    ()
  done

let () = time test ()
Run Code Online (Sandbox Code Playgroud)

输出:

ocamlopt bMl.ml -o bMl
./bMl
2041.075ms
Run Code Online (Sandbox Code Playgroud)

ocaml等价物基本上复制了go stdlib的实现,来自https://golang.org/src/unicode/utf8/utf8.go#L517

为什么ocaml代码这么慢?

Jul*_*ren 8

正如观察到的那样,您应该使用它Unix.gettimeofday来测量挂钟时间.Sys.opaque_identity但是,您可以使用它来阻止OCaml优化无用的操作,并且您可以使用ignore"返回单位"而不是表达式的通常值.共:

let time f x =
  let t = Unix.gettimeofday () in
  ignore (Sys.opaque_identity (f x));
  let t2 = Unix.gettimeofday () in
  ...

let test () =
  for i = 1 to 1_000_000_000 do
    ignore (Sys.opaque_identity (validUchar 23450));            
  done
Run Code Online (Sandbox Code Playgroud)

注意i = 1,如果你想要十亿次迭代,你需要它(在添加下划线之前我无法分辨的数字是10亿,OCaml允许).以前,您正在测量10亿加1次迭代.这不是那个区别.

你的详细定义validUchar并没有使其表现受益.请写一个微基准并确认.

最后,在进行了上面建议的更改并validUchar以更自然的方式编写之后,我得到一个与Go运行时相同的OCaml运行时...在ocamlopt参数中添加-O3之后.并且很容易确认这不是由于编译器"优化操作" - 在运行时间为0或接近0的值(如1.19e-06)f x中将time结果中的调用注释掉.

不要因为你对这个问题的回答而气馁.但是,期待任何一种"为什么这个基准有这个结果?" 对编程论坛的问题将得到类似的回答.


ivg*_*ivg 5

Sys.time不应该被用于时间的测量,因为它返回的处理器时间,而不是实时的.该Unix.gettimeofday功能是一个更好的候选人.或者,您可以使用time命令从shell计时程序.

作为旁注,基准测试很难,而且很容易产生误导性的结果.在你的特定情况下,如果你打开优化,两个编译器都会删除计算,因为它们没有被使用,并且会产生什么都不做的代码,因此相当快:)