Mercurial > rlm
comparison src/rlm/function_utils.clj @ 6:b8bbb0dbda7b
merging
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Thu, 01 Mar 2012 05:55:59 -0700 |
parents | 12d1367cf1aa 8565803376a4 |
children | 1065e7d615a4 |
comparison
equal
deleted
inserted
replaced
5:fca75c0e8f40 | 6:b8bbb0dbda7b |
---|---|
2 ;; | 2 ;; |
3 ;; Open source Liscence and all that | 3 ;; Open source Liscence and all that |
4 (ns | 4 (ns |
5 rlm.function-utils | 5 rlm.function-utils |
6 "Collection of Operators on Pure Functions" | 6 "Collection of Operators on Pure Functions" |
7 {:author "Robert McIntyre"} | 7 {:author "Robert McIntyre"}) |
8 (:use [clojure.contrib.profile])) | |
9 | 8 |
10 (def void ::void) | 9 (def void ::void) |
11 | 10 |
12 (comment | 11 (defn race |
13 | |
14 "Please help me out here. I'm trying to make a higher order function that takes | |
15 pure functions that are mathmaticaly the same but have different times and returns another | |
16 function that runs them both and returns the resut of the one that finishes first." | |
17 | |
18 | |
19 "here's a repl session: | |
20 | |
21 mobius> " (time (dotimes [_ 500]((mix-futures + +) 40 3 3 3 3 3))) " | |
22 Elapsed time: 85.792995 msecs | |
23 nil | |
24 mobius> " (time (dotimes [_ 500](+ 40 3 3 3 3 3))) " | |
25 Elapsed time: 6.956338 msecs | |
26 nil | |
27 mobius> " (time (dotimes [_ 500]((mix-threads + +) 40 3 3 3 3 3))) " | |
28 Elapsed time: 706.227065 msecs | |
29 nil | |
30 | |
31 | |
32 mobius> " (defn fast-five [& args] 5) " | |
33 #'mobius/fast-five | |
34 | |
35 mobius> " (defn slow-five [& args] (Thread/sleep 5000) (println "Oh YEAH!!!!") 5) " | |
36 #'mobius/slow-five | |
37 | |
38 mobius> " (profile (time (dotimes [_ 5000] (thread-five)))) " | |
39 \"Elapsed time: 12187.981587 msecs\" | |
40 Name mean min max count sum | |
41 create-atom 9621 2025 4433928 5000 48106830 | |
42 create-threads 5156 2724 2880268 5000 25783796 | |
43 kill-threads 91313 27866 11175718 5000 456567066 | |
44 loop 2124249 38482 18470781 5000 10621249899 | |
45 return 1242 838 5309 5000 6212626 | |
46 start-threads 252985 110348 12272835 5000 1264927953 | |
47 nil | |
48 | |
49 mobius> " (profile (time (dotimes [_ 5000] (future-five)))) " | |
50 \"Elapsed time: 607.266671 msecs\" | |
51 Name mean min max count sum | |
52 create-atom 1472 1047 31708 5000 7363139 | |
53 create-futures 30539 2514 1330660 5000 152697998 | |
54 kill-threads 54158 2444 3938833 5000 270792897 | |
55 loop 81117 8800 6083059 5000 405587516 | |
56 return 1215 838 618782 5000 6078146 | |
57 nil | |
58 | |
59 | |
60 | |
61 What can I improve here, and why is the future version sooo much faster than the | |
62 thread version? Is there a better way than using loop? | |
63 " | |
64 | |
65 ) | |
66 | |
67 | |
68 (defn race | |
69 "Takes any number of mathematically equal functions with | 12 "Takes any number of mathematically equal functions with |
70 possibly different run-times and returns a function that | 13 possibly different run-times and returns a function that |
71 runs each in a separate thread, returns the result from | 14 runs each in a separate thread, returns the result from |
72 the first thread which finishes, and cancels the other threads." | 15 the first thread which finishes, and cancels the other threads." |
73 {:author "Robert McIntyre"} | 16 {:author "Robert McIntyre"} |
106 (.countDown latch))))))) | 49 (.countDown latch))))))) |
107 answer @result] | 50 answer @result] |
108 (dorun (map future-cancel futures)) | 51 (dorun (map future-cancel futures)) |
109 answer)))) | 52 answer)))) |
110 | 53 |
111 | |
112 | |
113 (defn mix-threads | |
114 " Takes any number of pure functions that take the same arguments and | |
115 compute the same value and returns a function that runs each in a separate | |
116 thread, returns the result from the first thread which finshes, and cancels | |
117 the other threads. Explicitly uses nasty Threads. | |
118 | |
119 For example: | |
120 (do | |
121 (defn fun1 [] (Thread/sleep 5000) 5) | |
122 (defn fun2 [] (Thread/sleep 700000) 5) | |
123 (time ((mix fun1 fun2)))) | |
124 | |
125 Returns: | |
126 | Elapsed time: 5000.66214 msecs | |
127 5" | |
128 [& functions] | |
129 (fn [& args] | |
130 (let [result (prof :create-atom (atom void)) | |
131 threads | |
132 (prof :create-threads (map | |
133 (fn [fun] | |
134 (Thread. | |
135 (fn [] | |
136 (try (let [answer (apply fun args)] | |
137 (reset! result answer)) | |
138 (catch Exception _ nil))))) | |
139 functions))] | |
140 | |
141 (prof :start-threads (dorun (map #(.start %) threads))) | |
142 (prof :loop (loop [] | |
143 (if (= (deref result) void) | |
144 (recur) | |
145 (do (prof :kill-threads (dorun (map #(.stop %) threads))) | |
146 (prof :return (deref result))) | |
147 )))))) | |
148 | |
149 (defmacro defmix | 54 (defmacro defmix |
150 " Defines a function from any number of pure functions that take the same | 55 " Defines a function from any number of pure functions that take the same |
151 arguments and compute the same value which: | 56 arguments and compute the same value which: |
152 | 57 |
153 Runs each in a separate thread. | 58 Runs each in a separate thread. |
173 | 78 |
174 [name & functions] | 79 [name & functions] |
175 (let [doc-string (if (string? (first functions)) (first functions) "") | 80 (let [doc-string (if (string? (first functions)) (first functions) "") |
176 functions (if (string? (first functions)) (rest functions) functions) | 81 functions (if (string? (first functions)) (rest functions) functions) |
177 arglists (:arglists (meta (resolve (eval `(quote ~(first functions)))))) | 82 arglists (:arglists (meta (resolve (eval `(quote ~(first functions)))))) |
178 name (with-meta name (assoc (meta name) :arglists `(quote ~arglists) :doc doc-string))] | 83 name (with-meta name |
84 (assoc (meta name) :arglists `(quote ~arglists) | |
85 :doc doc-string))] | |
179 `(def ~name (mix ~@functions)))) | 86 `(def ~name (mix ~@functions)))) |
180 | |
181 | 87 |
182 (defn runonce | 88 (defn runonce |
183 "Decorator. returns a function which will run only once. Inspired | 89 "Decorator. returns a function which will run only once. Inspired |
184 by Halloway's version from lancet." | 90 by Halloway's version from lancet." |
185 {:author "Robert McIntyre"} | 91 {:author "Robert McIntyre"} |
190 (locking sentinel | 96 (locking sentinel |
191 (if (= @result sentinel) | 97 (if (= @result sentinel) |
192 (reset! result (apply function args)) | 98 (reset! result (apply function args)) |
193 @result))))) | 99 @result))))) |
194 | 100 |
195 | |
196 | |
197 ;I'm thinking this will be the docstring for mix eventually. | |
198 | |
199 ;; " Takes any number of pure functions that take the same arguments and | |
200 ;; compute the same value and returns a function that runs each in a separate | |
201 ;; thread, returns the result from the first thread which finshes, and cancels | |
202 ;; the other threads. | |
203 | |
204 ;; For example: | |
205 ;; (do | |
206 ;; (defn fun1 [] (Thread/sleep 5000) 5) | |
207 ;; (defn fun2 [] (Thread/sleep 700000) 5) | |
208 ;; (time ((mix fun1 fun2)))) | |
209 | |
210 ;; Returns: | |
211 ;; | Elapsed time: 5000.66214 msecs | |
212 ;; 5" |