clojure (… макрос с тайм-аутом)

Забавный вопрос.

1114 Итак, что же случилось? Хорошо, если вы выполните отладку с помощью gdb, вы увидите что-то вроде 3 переменных-членов (имена не точные):

  • _M_begin: указатель на первый элемент динамического массива
  • _M_end: указатель на один за последним элементом динамического массива
  • _M_capacity: указатель на один за последним элементом, который может быть сохранен в динамическом массиве

Реализация Таким образом, значение vector<T,Alloc>::size() обычно сводится к:

return _M_end - _M_begin;  // Note: _Mylast - _Myfirst in VC 2008

Теперь есть две вещи, которые следует учитывать при рассмотрении фактической возможной оптимизации:

  • будет ли эта функция встроенной? Вероятно: я не пишу компилятор, но это хорошая ставка, так как накладные расходы на вызов функции приведут к уменьшению фактического времени здесь, и так как это шаблонно, у нас будет весь код, доступный в модуле перевода
  • , результатом будет кэшируется (т. е. вроде имеет неназванную локальную переменную): вполне может быть, но вы не узнаете, если не разберете сгенерированный код

Другими словами:

  • Если вы сохраните size самостоятельно, есть большая вероятность, что он будет таким же быстрым, как компилятор мог его получить ...
  • Но вы подвергаете себя техническому разрушению: что если вдруг вы измените вектор и не обновите переменную;)?

В любом случае, я серьезно сомневаюсь, что это стоит хлопот. В лучшем случае это микрооптимизация, которая вряд ли принесет большую пользу.

8
задан Arthur Ulfeldt 5 November 2009 в 21:17
поделиться

2 ответа

На этот вопрос есть лучшие ответы здесь: Выполнение функции с тайм-аутом

Futures на помощь!

user=> (let [f (future (reduce * (range 1 1001)))]
  (.get f 1 java.util.concurrent.TimeUnit/MILLISECONDS))
java.util.concurrent.TimeoutException (NO_SOURCE_FILE:0)

И чтобы сделать макрос из этого:

(defmacro time-limited [ms & body]
  `(let [f# (future ~@body)]
     (.get f# ~ms java.util.concurrent.TimeUnit/MILLISECONDS)))

Итак, вы можете сделать это:

user=> (time-limited 1 (reduce * (range 1 1001)))
java.util.concurrent.TimeoutException (NO_SOURCE_FILE:0)
user=> (time-limited 1 (reduce * (range 1 101)))
93326215443944152681699238856266700490715968264381621468592963895217599993229915
608941463976156518286253697920827223758251185210916864000000000000000000000000
22
ответ дан 5 December 2019 в 06:38
поделиться

Я не уверен, что это возможно без выполнения выражения в отдельном потоке. Причина в том, что если поток занят обработкой выражения, вы не можете внедрить код для генерации исключения.

Версия с потоком монитора, который генерирует исключение, если выражение занимает слишком много времени, определенно возможна, однако выброшенное исключение будет из потока монитора, а не из потока, в котором выполняется выражение. Тогда не было бы способа остановить его, за исключением отправки этому потоку прерывания, которое он мог бы проигнорировать, если вы не закодировали его в выражении.

Если приемлемо иметь версию, которая запускает выражение в в отдельной ветке, дайте мне знать, и я могу опубликовать образец кода. Иначе, ваш лучший выбор звучит так, как будто это было бы написать основной цикл / рекурсию выражения таким образом, чтобы он проверял, сколько времени он занял на каждой итерации, и генерировал исключение, если оно превышало границу. Извините, если это не совсем то, что вам нужно ...

2
ответ дан 5 December 2019 в 06:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: