|
1 | 1 | (ns ^{:author "Ryan Smith"
|
2 |
| - :doc "Provide a variant of `core.async/go` that works with manifold's deferreds and executors. Utilizes core.async's state-machine generator, so core.async must be available as a dependency."} |
| 2 | + :doc "Provide a variant of `core.async/go` that works with manifold's deferreds and executors. Utilizes core.async's state-machine generator, so core.async must be provided as a dependency."} |
3 | 3 | manifold.go-off
|
4 | 4 | (:require [manifold
|
5 | 5 | [executor :as ex]
|
|
16 | 16 | d))
|
17 | 17 |
|
18 | 18 | (defn <!
|
19 |
| - "takes value from deferred. Must be called inside a (go ...) block. Will |
20 |
| - return nil if closed. Will park if nothing is available. If an error |
21 |
| - is thrown inside the body, that error will be placed as the return value. |
| 19 | + "Takes value from a deferred/stream. Must be called inside a (go ...) block. Will |
| 20 | + return nil if a stream is closed. Will park if nothing is available. If an error |
| 21 | + is thrown inside the body, that error will be placed as the return value. |
22 | 22 |
|
23 |
| - N.B. To make `go-off` usage idiomatic with the rest of manifold, use `<!?` |
24 |
| - instead of this directly." |
| 23 | + N.B. To make `go-off` usage idiomatic with the rest of manifold, use `<!?` |
| 24 | + instead." |
25 | 25 | [port]
|
26 | 26 | (assert nil "<! used not in (go-off ...) block"))
|
27 | 27 |
|
28 | 28 | (defmacro <!?
|
29 |
| - "takes a val from port. Must be called inside a (go-off ...) block. |
30 |
| - Will park if nothing is available. If value that is returned is |
31 |
| - a Throwable, will re-throw." |
| 29 | + "Takes a val from a deferred/stream. Must be called inside a (go-off ...) block. |
| 30 | + Will park if nothing is available. If value that is returned is a Throwable, |
| 31 | + it will re-throw." |
32 | 32 | [port]
|
33 | 33 | `(let [r# (<! ~port)]
|
34 | 34 | (if (instance? Throwable r#)
|
|
93 | 93 |
|
94 | 94 | (defmacro go-off
|
95 | 95 | "Asynchronously executes the body on manifold's default executor, returning
|
96 |
| - immediately to the calling thread. Additionally, any visible calls to <!? |
97 |
| - and <! deferred operations within the body will block (if necessary) |
98 |
| - by 'parking' the calling thread rather than tying up an OS thread. |
99 |
| - Upon completion of the operation, the body will be resumed. |
100 |
| -
|
101 |
| - Returns a deferred which will receive the result of the body when |
102 |
| - completed. If the body returns a deferred, the result will be unwrapped |
103 |
| - until a non-deferable value is available to be placed onto the return deferred. |
104 |
| -
|
105 |
| - This method is intended to be similar to `core.async/go`, and even utilizes the |
106 |
| - underlying state machine related functions from `core.async`. It's been designed |
107 |
| - to address the following major points from core.async & vanilla manifold deferreds: |
108 |
| -
|
109 |
| - - `core.async/go` assumes that all of your code is able to be purely async |
110 |
| - and will never block the handling threads. go-off removes the concept of handling |
111 |
| - threads, which means blocking is not an issue, but if you spawn too many of these you |
112 |
| - can create too many threads for the OS to handle. |
113 |
| - - `core.async/go` has absolutely no way of bubbling up exceptions and assumes all |
114 |
| - code will be defensively written, which differs from how clojure code blocks work |
115 |
| - outside of the async world. |
116 |
| - - `deferred/let-flow` presumes that every deferrable needs to be resolved. This prevents |
117 |
| - more complex handling of parallelism or being able to pass deferreds into other functions |
118 |
| - from within the `let-flow` block |
119 |
| - - `deferred/chain` only works with single deferreds, which means having to write code in |
120 |
| - unnatural ways to handle multiple deferreds." |
| 96 | + immediately to the calling thread. Additionally, any visible calls to <!? |
| 97 | + and <! deferred operations within the body will block (if necessary) |
| 98 | + by 'parking' the calling thread rather than tying up an OS thread. |
| 99 | + Upon completion of the operation, the body will be resumed. |
| 100 | +
|
| 101 | + Returns a deferred which will receive the result of the body when |
| 102 | + completed. If the body returns a deferred, the result will be unwrapped |
| 103 | + until a non-deferrable value is available to be placed onto the return deferred. |
| 104 | +
|
| 105 | + This method is intended to be similar to `core.async/go`, and even utilizes the |
| 106 | + underlying state machine-related functions from `core.async`. It's been designed |
| 107 | + to address the following major points from core.async & vanilla manifold deferreds: |
| 108 | +
|
| 109 | + - `core.async/go` assumes that all of your code is able to be purely async |
| 110 | + and will never block the handling threads. go-off removes the concept of handling |
| 111 | + threads, which means blocking is not an issue, but if you spawn too many of these you |
| 112 | + can create too many threads for the OS to handle. |
| 113 | + - `core.async/go` has no built-in way of handling exceptions and assumes all async |
| 114 | + code will be either written defensively, or have custom error propagation, which |
| 115 | + differs from how clojure code blocks typically work outside of the async world. |
| 116 | + - `deferred/let-flow` presumes that every deferrable needs to be resolved. This prevents |
| 117 | + more complex handling of parallelism or being able to pass deferreds into other functions |
| 118 | + from within the `let-flow` block. |
| 119 | + - `deferred/chain` only works with single deferreds, which means having to write code in |
| 120 | + unnatural ways to handle multiple deferreds." |
121 | 121 | [& body]
|
122 | 122 | `(go-off-executor (ex/execute-pool) ~@body))
|
123 | 123 |
|
124 |
| -(go-off "cat") |
125 | 124 |
|
126 |
| -@(go-off (+ (<!? (d/future 10)) |
127 |
| - (<!? (d/future 20)))) ;; ==> 30 |
| 125 | +(comment |
| 126 | + (go-off "cat") |
| 127 | + |
| 128 | + @(go-off (+ (<!? (d/future 10)) |
| 129 | + (<!? (d/future 20)))) ;; ==> 30 |
| 130 | + |
| 131 | + ) |
0 commit comments