在OCaml中中断调用

在OCaml中中断调用,ocaml,Ocaml,如果计算时间太长,我想中断一个调用,就像这样 try do_something () with Too_long -> something_else () 在OCaml中可以做类似的事情吗?函数“Dou_something”可能无法修改。(我猜您是在Linux上) 了解更多关于-s的信息。您可以将Ocaml用于Sys.sigallarm和模块(尤其是Unix.setitimer)标准库中没有内置工具来执行此精确操作,但实现起来相当简单。使用Thread模块,运行一个线程来执行主程序

如果计算时间太长,我想中断一个调用,就像这样

try
   do_something ()
with Too_long -> something_else ()
在OCaml中可以做类似的事情吗?函数“Dou_something”可能无法修改。

(我猜您是在Linux上)


了解更多关于-s的信息。您可以将Ocaml用于
Sys.sigallarm
和模块(尤其是
Unix.setitimer

标准库中没有内置工具来执行此精确操作,但实现起来相当简单。使用
Thread
模块,运行一个线程来执行主程序,并运行一个监视线程,如果程序持续时间过长,该线程将终止程序。下面是一个开始的实现:

type 'a state =
    | Running
    | Finished of 'a
    | Failed of exn
    | Cancelled of 'a

let bounded_run d f g x =
    let state = ref Running in
    let p = ref None in
    let m = ref None in
    let cancel t' = match !t' with
      | Some(t) -> Thread.kill t
      | None -> ()
    in
    let program () =
      (try state := Finished(f x)
       with exn -> state := Failed (exn));
      cancel m;
    in
    let monitor () =
      Thread.delay d;
      match !state with
        | Running -> cancel p; state := Cancelled(g x)
        | _ -> ()
    in
    p := Some(Thread.create program ());
    m := Some(Thread.create monitor p);
    (match !m with
      | None -> ()
      | Some(t) -> Thread.join t);
    !state
调用
bounded\u run d f g x
最多运行
fx
秒,如果计算在给定时间内运行,则返回
Finished(f x)
。如果计算引发异常,它可能返回
Failed(exn)
。当计算持续时间过长时,返回值被取消(gx)


此实现有许多默认值,例如,状态和返回值应具有不同的类型(值
Running
在返回的类型中不可能),它不使用互斥锁来阻止对
p
m
变量的并发访问,这些变量包含对我们使用的线程的引用。虽然它的边缘很粗糙,但这应该让您开始,但对于更高级的使用,您还应该学习事件或第三方库,如Lwt或Async–前者将要求您更改函数。

一般来说,中断函数的唯一方法是使用信号,正如Basile建议的那样。不幸的是,控制流将被传输到信号处理程序,因此您将无法返回您喜欢的值。为了获得更细粒度的控制,您可以在单独的线程中运行您的
do\u something
。第一个近似值为以下函数:

exception Timeout

let with_timeout timeout f =
  let result = ref None in
  let finished = Condition.create () in
  let guard = Mutex.create () in
  let set x =
    Mutex.lock guard;
    result := Some x;
    Mutex.unlock guard in
  Mutex.lock guard;
  let work () =
    let x = f () in
    set x;
    Condition.signal finished in
  let delay () =
    Thread.delay timeout;
    Condition.signal finished in
  let task = Thread.create work () in
  let wait = Thread.create delay () in
  Condition.wait finished guard;
  match !result with
  | None ->
    Thread.kill task;
    raise Timeout
  | Some x ->
    Thread.kill wait;
    x
使用线程和信号函数的解决方案有一些缺点。例如,线程在特定的iterruption点的OCaml中切换,通常这是任何分配。所以,如果您的代码不执行任何分配或外部调用,那么它可能永远不会向其他线程屈服,并将永远运行。这种函数的一个很好的例子是
let rec f()=f()
。在这种情况下,您应该在另一个进程而不是线程中运行函数。OCaml中有许多用于多处理的库,仅举几个例子:


  • 但要小心,这通常是正确的方法,因为不分配的函数不会发出信号。但是,不分配和需要超时的函数通常是一种非常特殊的情况。