Poszukuję makra, które wygeneruje wyjątek, jeśli wyrażenie trwa dłużej niż X sekund.clojure (with-timeout ... macro)
Odpowiedz
To pytanie ma lepszą odpowiedź tutaj: Executing a function with a timeout
Futures na ratunek!
user=> (let [f (future (reduce * (range 1 1001)))]
(.get f 1 java.util.concurrent.TimeUnit/MILLISECONDS))
java.util.concurrent.TimeoutException (NO_SOURCE_FILE:0)
I zrobić makro z nim:
(defmacro time-limited [ms & body]
`(let [f# (future [email protected])]
(.get f# ~ms java.util.concurrent.TimeUnit/MILLISECONDS)))
Więc można to zrobić:
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
Nie jestem pewien, czy jest to możliwe bez uruchamiania wyrażenia w osobnym wątku. Powodem jest to, że jeśli wątek jest zajęty przetwarzaniem wyrażenia, nie można wstrzyknąć kodu, aby rzucić wyjątek.
Wersja z wątkiem monitora, który zgłasza wyjątek, jeśli wyrażenie trwa zbyt długo, jest zdecydowanie możliwa, jednak zgłoszony wyjątek pochodzi z wątku monitora, a nie z wątku, w którym wyrażenie jest uruchomione. Wtedy nie byłoby sposobu, aby powstrzymać go przed wysłaniem tego wątku przerwania, które mogłoby zignorować, gdybyś nie zakodował tego w wyrażeniu.
Jeśli możliwe jest posiadanie wersji, która uruchamia wyrażenie w oddzielnym wątku, daj mi znać i mogę wysłać przykładowy kod. W przeciwnym razie twój najlepszy zakład brzmi, jakby to było napisać główną pętlę/rekursję wyrażenia w taki sposób, aby sprawdzał, ile czasu zajęło mu wykonanie każdej iteracji i zgłasza wyjątek, jeśli przekroczył granicę. Przepraszam, jeśli to nie całkiem to, czego potrzebujesz ...
Może (z-limitem czasu ... może działać jak pętla, i być punktem powtarzania, i za każdym razem, gdy trafisz (z-timeout sprawdza zegar i zatrzymuje wykonywanie (lub zgłasza wyjątek), jeśli zostało uruchomione do Jednak to użycie musiałoby być * wewnątrz * funkcji, nie owijać tej funkcji, ale nie powoduje efektów ubocznych w innych ogólnie zniechęconych funkcjach [Myślę o wszystkich ostrzeżeniach wokół (wiązanie)? – nilamo
natknąłem tego wątku niedawno podczas zadaje to samo pytanie. Nie byłem w pełni zadowolony z udzielonych odpowiedzi, więc wybrałem alternatywne rozwiązanie. To rozwiązanie uruchomi twój kod w bieżącym wątku i zakręcie przyszłości, aby go przerwać po ustawionym czasie oczekiwania w ms.
(defn invoke-timeout [f timeout-ms]
(let [thr (Thread/currentThread)
fut (future (Thread/sleep timeout-ms)
(.interrupt thr))]
(try (f)
(catch InterruptedException e
(throw (TimeoutException. "Execution timed out!")))
(finally
(future-cancel fut)))))
(defmacro timeout [ms & body] `(invoke-timeout (fn [] [email protected]) ~ms))
będzie go używać w kodzie tak:
(timeout 1000 your-code)
LUB
(invoke-timeout #(your-code) 1000)
Jedno zastrzeżenie, aby pamiętać, że your-code
nie może złapać InterruptedException
używany do wyzwalania TimeoutException. Używam tego do testowania i działa dobrze.
Aby uzyskać dodatkowe zastrzeżenia, zobacz stronę Thread.interrupt()
javadoc.
Możesz zobaczyć ten kod w użyciu here.
- 1. Clojure macro jako funkcja/"Partial" dla makr?
- 2. metal: use-macro and metal: define-macro within Five ViewPageTemplateFile
- 3. Eclipse Macro Expansion Color
- 4. Macro przed nazwą klasy
- 5. Macro do definiowania cechę aliasy
- 6. Dlaczego Clojure's for macro akceptuje tylko jedno wyrażenie ciała?
- 7. W clojure, jak zastosować makro do listy?
- 8. Vim macro: Inkrementacja liczb w kolejnych wierszach
- 9. Uzyskiwanie parametrów z notatki Scala Macro
- 10. Ucieczki wsporniki w Clojure
- 11. Dynamiczne wywoływanie metod w makrze Clojure?
- 12. Wykonaj plik .bat z programu Excel VBA Macro
- 13. User Sub z parametrami opcjonalnymi - niewidoczne w oknie Macro
- 14. Najlepszy sposób na opanowanie systemu Racket Macro dla wymagających programistów
- 15. ostrzeżenie Odbicie w kodzie generowane przez Clojure makro
- 16. Clojure stripMargin
- 17. Clojure: = vs ==
- 18. Zalety Clojure
- 19. Kompilacja Clojure?
- 20. Clojure zamknięcie
- 21. Arkusze Clojure
- 22. Clojure Trygonometria
- 23. Kłopoty z Clojure cytując-paren `(...) makro
- 24. Clojure: praca z java.util.HashMap w idiomatycznym stylu Clojure
- 25. Skład funkcji w Clojure?
- 26. Clojure: postanowienie deklaruje symbol
- 27. Analizowanie makro argumenty Clojure
- 28. Clojure błąd oceny symbol
- 29. Clojure składnia argumentu funkcja
- 30. Clojure infinite loop
Po prostu być clear - przyszłość zdecydowanie działa, ale uruchomi dostarczony expr w osobnym wątku. Większość czasu to nie stanowi problemu, szczególnie jeśli piszesz referencyjny, przejrzysty kod, ale jeśli używasz (wiążąc ...) to może zdecydowanie powodować pewne problemy. – levand
Przyszłość może nadal istnieć po upływie limitu czasu. Użyj 'future-cancel' po upływie limitu czasu, jak opisano [w tym wątku] (http://stackoverflow.com/a/6697469/682672). – neatonk
Bardziej odporną wersję tego, która używa wątków zamiast futures można znaleźć [tutaj] (http://stackoverflow.com/a/6697356/682672) – neatonk