Unix 为函数设置计时器
我已经定义了一个值列表:Unix 为函数设置计时器,unix,time,timer,signals,ocaml,Unix,Time,Timer,Signals,Ocaml,我已经定义了一个值列表: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设置一个最大运行时间。例如,如果fd超过某个时间maximal,fd的执行停止,我们继续执行数据的下一个元素 有人知道怎么做吗 更新1: 在评论之后,我想补充一点,将f应用到数据的大部分元素将引发异常。这是正常的,也是可以接受
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
设置一个最大运行时间。例如,如果fd
超过某个时间maximal
,fd
的执行停止,我们继续执行数据的下一个元素
有人知道怎么做吗
更新1:
在评论之后,我想补充一点,将f
应用到数据的大部分元素
将引发异常。这是正常的,也是可以接受的。因此,代码如下所示:
List.iter
(fun d ->
try
(f d)
with
| e ->
printf "%s\n" (Printexc.to_string e))
data
这样的东西可能适合你:
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 = ()
#
(这段代码还没有经过彻底的测试,但它展示了一种可行的方法。)
更新
如注释所示,如果fx
可能引发异常(或者如果您将报警用于其他目的),则此代码不适用。我鼓励gsg发布他/她的改进解决方案。编辑似乎已被拒绝。这是基于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
您应该按如下方式编写循环:List.iter f data
。您的方法引入了不必要的二次复杂性。(对不起,这不是对你的计时问题的回答。)虽然我认为这是最正确的方法,但如果fx
上升,你会遇到麻烦。将有一个挂起的SIGALRM
,并且仍将安装引发超时的处理程序。此外,如果存在一个现有的SIGALRM
处理程序,无论fx
是否提升,它都将被无声地踩踏。更好的方法是使用Sys.signal
保存旧的处理程序,并无条件地恢复它:类似于try。。。;使用exn->finish()完成();exn
,其中finish
恢复旧处理程序并取消任何挂起的报警。阿门。但是,如果事情处于已知状态(代码不是通用库的一部分,等等),也许一个粗略的解决方案是可以的。@gsg如果fx引发
==>您的意思是当fx
引发异常时,您会遇到麻烦吗?我的fx
的一部分将以异常结束,因此此代码不适用?是的,这就是我的意思。如果fx
可能引发异常,则需要对代码进行一点修改。@gsg此计时器应该包装整个fx
,这很复杂(这就是它需要时间的原因),并且可能引发多种类型的异常。我真的很想更正它,但我不熟悉Sys或Unix。我将要更新OP,你能帮我解决吗?谢谢!我还是不确定编辑出了什么事?哦,好吧。
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