5

我已经定义了一个值列表:data : int list和一个函数f: int -> unit,以及一段代码:

for i = 0 to (List.length data) - 1 do
  let d = List.nth data i in
  f d
done

现在,我想为f. 例如,如果f d超过一定时间maximal,则f d停止执行,继续执行下一个元素data

有谁知道该怎么做?

更新1:

在评论之后,我想补充一点,对f大部分元素的应用data最终会引发异常。这是正常的并被接受。所以代码看起来像:

List.iter
  (fun d ->
     try
       (f d)
     with
     | e ->
       printf "%s\n" (Printexc.to_string e))
data
4

2 回答 2

5

这样的事情可能对你有用:

exception Timeout

let run_with_timeout t f x =
    try
        Sys.set_signal Sys.sigalrm (Sys.Signal_handle (fun _ -> raise Timeout));
        ignore (Unix.alarm t);
        f x;
        ignore (Unix.alarm 0);
        Sys.set_signal Sys.sigalrm Sys.Signal_default
    with Timeout -> Sys.set_signal Sys.sigalrm Sys.Signal_default

这是一个展示它如何工作的会话:

$ ocaml
        OCaml version 4.00.1

# #load "unix.cma";;
# #use "rwt.ml";;
exception Timeout
val run_with_timeout : int -> ('a -> 'b) -> 'a -> unit = <fun>
# run_with_timeout 2 Printf.printf "yes\n";;
yes
- : unit = ()
# run_with_timeout 2 (fun () -> while true do () done) ();;
- : unit = ()
#

您的代码将是这样的:

List.iter (run_with_timeout 10 f) data

(此代码尚未经过彻底测试,但它显示了一种可行的方法。)

更新

f x正如评论所示,如果可能引发异常(或者如果您将警报用于其他目的),则此代码不适合。我鼓励 gsg 发布他/她改进的解决方案。编辑似乎已被拒绝。

于 2013-11-10T05:56:41.370 回答
3

这是基于 Jeffrey 的回答,并进行了一些修改以提高异常安全性:

exception Timeout

let run_with_timeout timeout f x =
  let old_handler = Sys.signal Sys.sigalrm
    (Sys.Signal_handle (fun _ -> raise Timeout)) in
  let finish () =
    ignore (Unix.alarm 0);
    ignore (Sys.signal Sys.sigalrm old_handler) in
  try
    ignore (Unix.alarm timeout);
    ignore (f x);
    finish ()
  with Timeout -> finish ()
   | exn -> finish (); raise exn
于 2013-11-10T15:39:44.243 回答