我定义了一个值列表: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
的下一个元素。
有谁知道怎么做?
UPDATE1:
在评论之后,我想补充一点,f
对data
的大部分元素的应用最终会引发异常。这是正常的并被接受。所以代码看起来像:
List.iter
(fun d ->
try
(f d)
with
| e ->
printf "%s\n" (Printexc.to_string e))
data
答案 0 :(得分: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发布他/她改进的解决方案。编辑似乎被拒绝了。
答案 1 :(得分:1)
这是基于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