comparison src/rlm/function_utils.clj @ 1:8565803376a4

upgrading source to work with clojure 1.4
author Robert McIntyre <rlm@mit.edu>
date Tue, 28 Feb 2012 13:26:34 -0600
parents 78a630e650d2
children b8bbb0dbda7b
comparison
equal deleted inserted replaced
0:78a630e650d2 1:8565803376a4
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
12 (comment
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 10
68 (defn mix 11 (defn mix
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
78 (future (deliver result (apply fun args))))) 21 (future (deliver result (apply fun args)))))
79 answer @result] 22 answer @result]
80 (dorun (map future-cancel futures)) 23 (dorun (map future-cancel futures))
81 answer)))) 24 answer))))
82 25
26 ;; (defn mix-threads
27 ;; " Takes any number of pure functions that take the same arguments and
28 ;; compute the same value and returns a function that runs each in a separate
29 ;; thread, returns the result from the first thread which finshes, and cancels
30 ;; the other threads. Explicitly uses nasty Threads.
83 31
84 32 ;; For example:
85 33 ;; (do
86 (defn mix-threads 34 ;; (defn fun1 [] (Thread/sleep 5000) 5)
87 " Takes any number of pure functions that take the same arguments and 35 ;; (defn fun2 [] (Thread/sleep 700000) 5)
88 compute the same value and returns a function that runs each in a separate 36 ;; (time ((mix fun1 fun2))))
89 thread, returns the result from the first thread which finshes, and cancels
90 the other threads. Explicitly uses nasty Threads.
91
92 For example:
93 (do
94 (defn fun1 [] (Thread/sleep 5000) 5)
95 (defn fun2 [] (Thread/sleep 700000) 5)
96 (time ((mix fun1 fun2))))
97 37
98 Returns: 38 ;; Returns:
99 | Elapsed time: 5000.66214 msecs 39 ;; | Elapsed time: 5000.66214 msecs
100 5" 40 ;; 5"
101 [& functions] 41 ;; [& functions]
102 (fn [& args] 42 ;; (fn [& args]
103 (let [result (prof :create-atom (atom void)) 43 ;; (let [result (prof :create-atom (atom void))
104 threads 44 ;; threads
105 (prof :create-threads (map 45 ;; (prof :create-threads (map
106 (fn [fun] 46 ;; (fn [fun]
107 (Thread. 47 ;; (Thread.
108 (fn [] 48 ;; (fn []
109 (try (let [answer (apply fun args)] 49 ;; (try (let [answer (apply fun args)]
110 (reset! result answer)) 50 ;; (reset! result answer))
111 (catch Exception _ nil))))) 51 ;; (catch Exception _ nil)))))
112 functions))] 52 ;; functions))]
113 53
114 (prof :start-threads (dorun (map #(.start %) threads))) 54 ;; (prof :start-threads (dorun (map #(.start %) threads)))
115 (prof :loop (loop [] 55 ;; (prof :loop (loop []
116 (if (= (deref result) void) 56 ;; (if (= (deref result) void)
117 (recur) 57 ;; (recur)
118 (do (prof :kill-threads (dorun (map #(.stop %) threads))) 58 ;; (do (prof :kill-threads (dorun (map #(.stop %) threads)))
119 (prof :return (deref result))) 59 ;; (prof :return (deref result)))))))))
120 ))))))
121 60
122 (defmacro defmix 61 (defmacro defmix
123 " Defines a function from any number of pure functions that take the same 62 " Defines a function from any number of pure functions that take the same
124 arguments and compute the same value which: 63 arguments and compute the same value which:
125 64
146 85
147 [name & functions] 86 [name & functions]
148 (let [doc-string (if (string? (first functions)) (first functions) "") 87 (let [doc-string (if (string? (first functions)) (first functions) "")
149 functions (if (string? (first functions)) (rest functions) functions) 88 functions (if (string? (first functions)) (rest functions) functions)
150 arglists (:arglists (meta (resolve (eval `(quote ~(first functions)))))) 89 arglists (:arglists (meta (resolve (eval `(quote ~(first functions))))))
151 name (with-meta name (assoc (meta name) :arglists `(quote ~arglists) :doc doc-string))] 90 name (with-meta name
91 (assoc (meta name) :arglists `(quote ~arglists)
92 :doc doc-string))]
152 `(def ~name (mix ~@functions)))) 93 `(def ~name (mix ~@functions))))
153
154 94
155 (defn runonce 95 (defn runonce
156 "Decorator. returns a function which will run only once. Inspired 96 "Decorator. returns a function which will run only once. Inspired
157 by Halloway's version from lancet." 97 by Halloway's version from lancet."
158 {:author "Robert McIntyre"} 98 {:author "Robert McIntyre"}
163 (locking sentinel 103 (locking sentinel
164 (if (= @result sentinel) 104 (if (= @result sentinel)
165 (reset! result (apply function args)) 105 (reset! result (apply function args))
166 @result))))) 106 @result)))))
167 107
168
169
170 ;I'm thinking this will be the docstring for mix eventually.
171
172 ;; " Takes any number of pure functions that take the same arguments and
173 ;; compute the same value and returns a function that runs each in a separate
174 ;; thread, returns the result from the first thread which finshes, and cancels
175 ;; the other threads.
176
177 ;; For example:
178 ;; (do
179 ;; (defn fun1 [] (Thread/sleep 5000) 5)
180 ;; (defn fun2 [] (Thread/sleep 700000) 5)
181 ;; (time ((mix fun1 fun2))))
182
183 ;; Returns:
184 ;; | Elapsed time: 5000.66214 msecs
185 ;; 5"