Модуль Timeoutable вычислений


Определяет простой модуль для timeoutable вычислений, с возможностью возврата произвольные промежуточные результаты по таймауту или конечное значение в противном случае. Он также позволяет возвращать значения по умолчанию.

Реализация использует Unix.истечении отправляет, чтобы определить интервалы ожидания с второй резолюции. Есть небольшие накладные расходы на запуск вычислений, потому что мы должны создать обработчики сигналов и только потом вызываем метод функтор-это "вызов". Кроме того, есть небольшие накладные расходы на возврат результата вычислений (частичной или окончательной), как у нас чтобы восстановить исходный обработчик истечении отправляет сигнал. Они должны амортизировать, если фактическое расчет занимает некоторое время (секунды) - и это контекст, в котором вы хотели бы в любом случае использовать модуль ожидания.

Для использования этого, определить свой собственный модуль уважая интерфейс Timeoutable. Реализовать функции в вызове функции. Если вам нужно вернуть посредника результаты на тайм-аут, поймать исключение CallTimeout и вернуть значение параметра. Если код, который вы пишете поднимает и не поймать исключение, вызов функции будет возвращать значение по умолчанию. То же самое произойдет, если вы не заметили Исключение CallTimeout в коде и его тайм-ауты.

exception CallTimeout;;

type ('p,'f) result =
    [ `Timeout of 'p (* partial result *)
    | `Done of 'f    (* final result   *)
    | `Error of string
    ]

module type Timeoutable =
sig
  type ('p,'f) t
  type arg

  val default: ('p,'f) t
  val call: arg -> ('p,'f) t

end

module Timeout (U:Timeoutable) = 
struct
    let sigalrm_handler = Sys.Signal_handle (fun _ -> raise CallTimeout);;

    let tcall arg timeout =
        let old_behaviour = Sys.signal Sys.sigalrm sigalrm_handler in
        let reset_sigalrm () = Sys.set_signal Sys.sigalrm old_behaviour in
          ignore (Unix.alarm timeout);
      try
            let res = U.call arg in reset_sigalrm(); res;
      with exn -> reset_sigalrm(); U.default;
end

Используя его:

module AddTwo = struct
  type ('p,'f) t = (int,int) Timeout.result
  type arg = int

  let default = `Error "could not complete AddTwo"

  let call a =
    try
      ignore(Unix.sleep 2);
      `Done (a+2)
    with
      | Timeout.CallTimeout-> `Timeout (a+1)
end 


module Test = Timeout.Timeout(AddTwo);;


let r = Test.tcall 7 10 in
  match r with
    | `Done x    -> print_int x
    | `Timeout b -> print_string "Function timeout, partial result: "; print_int b
    | `Error s   -> print_string s

Любые идеи о том, как улучшить это? Какие еще особенности необходимо timeoutable вычислений?



224
14
задан 2 декабря 2011 в 11:12 Источник Поделиться
Комментарии