@@ -18,7 +18,33 @@ to validate go blocks do not invoke core.async blocking operations.
18
18
Property is read once, at namespace load time. Recommended for use
19
19
primarily during development. Invalid blocking calls will throw in
20
20
go block threads - use Thread.setDefaultUncaughtExceptionHandler()
21
- to catch and handle."
21
+ to catch and handle.
22
+
23
+ Use the Java system property `clojure.core.async.executor-factory`
24
+ to specify a function that will provide ExecutorServices for
25
+ application-wide use by core.async in lieu of its defaults. The
26
+ property value should name a fully qualified var. The function
27
+ will be passed a keyword indicating the context of use of the
28
+ executor, and should return either an ExecutorService, or nil to
29
+ use the default. Results per keyword will be cached and used for
30
+ the remainder of the application. Possible context arguments are:
31
+
32
+ :io - used in async/io-thread, for :io workloads in flow/process,
33
+ and for dispatch handling if no explicit dispatch handler is
34
+ provided (see below)
35
+
36
+ :mixed - used by async/thread and for :mixed workloads in
37
+ flow/process
38
+
39
+ :compute - used for :compute workloads in flow/process
40
+
41
+ :core-async-dispatch - used for completion fn handling (e.g. in put!
42
+ and take!, as well as go block IOC thunk processing) throughout
43
+ core.async. If not supplied the ExecutorService for :io will be
44
+ used instead.
45
+
46
+ The set of contexts may grow in the future so the function should
47
+ return nil for unexpected contexts."
22
48
(:refer-clojure :exclude [reduce transduce into merge map take partition
23
49
partition-by bounded-count])
24
50
(:require [clojure.core.async.impl.protocols :as impl]
@@ -29,7 +55,6 @@ to catch and handle."
29
55
[clojure.core.async.impl.ioc-macros :as ioc]
30
56
clojure.core.async.impl.go ; ; TODO: make conditional
31
57
[clojure.core.async.impl.mutex :as mutex]
32
- [clojure.core.async.impl.concurrent :as conc]
33
58
)
34
59
(:import [java.util.concurrent.atomic AtomicLong]
35
60
[java.util.concurrent.locks Lock]
@@ -281,6 +306,12 @@ to catch and handle."
281
306
(let [flag (alt-flag )
282
307
ports (vec ports) ; ; ensure vector for indexed nth
283
308
n (count ports)
309
+ _ (loop [i 0 ] ; ; check for invalid write op
310
+ (when (< i n)
311
+ (let [port (nth ports i)]
312
+ (when (vector? port)
313
+ (assert (some? (port 1 )) " can't put nil on channel" )))
314
+ (recur (unchecked-inc i))))
284
315
^ints idxs (random-array n)
285
316
priority (:priority opts)
286
317
ret
@@ -463,33 +494,42 @@ to catch and handle."
463
494
[& body]
464
495
(#'clojure.core.async.impl.go/go-impl &env body))
465
496
466
- (defonce ^:private ^Executor thread-macro-executor
467
- (Executors/newCachedThreadPool (conc/counted-thread-factory " async-thread-macro-%d" true )))
468
-
469
497
(defn thread-call
470
498
" Executes f in another thread, returning immediately to the calling
471
499
thread. Returns a channel which will receive the result of calling
472
- f when completed, then close."
473
- [f]
474
- (let [c (chan 1 )]
475
- (let [binds (Var/getThreadBindingFrame )]
476
- (.execute thread-macro-executor
477
- (fn []
478
- (Var/resetThreadBindingFrame binds)
479
- (try
480
- (let [ret (f )]
481
- (when-not (nil? ret)
482
- (>!! c ret)))
483
- (finally
484
- (close! c))))))
485
- c))
500
+ f when completed, then close. workload is a keyword that describes
501
+ the work performed by f, where:
502
+
503
+ :io - may do blocking I/O but must not do extended computation
504
+ :compute - must not ever block
505
+ :mixed - anything else (default)
506
+
507
+ when workload not supplied, defaults to :mixed"
508
+ ([f] (thread-call f :mixed ))
509
+ ([f workload]
510
+ (let [c (chan 1 )
511
+ returning-to-chan (fn [bf]
512
+ #(try
513
+ (when-some [ret (bf )]
514
+ (>!! c ret))
515
+ (finally (close! c))))]
516
+ (-> f bound-fn* returning-to-chan (dispatch/exec workload))
517
+ c)))
486
518
487
519
(defmacro thread
488
520
" Executes the body in another thread, returning immediately to the
489
521
calling thread. Returns a channel which will receive the result of
490
522
the body when completed, then close."
491
523
[& body]
492
- `(thread-call (^:once fn* [] ~@body)))
524
+ `(thread-call (^:once fn* [] ~@body) :mixed ))
525
+
526
+ (defmacro io-thread
527
+ " Executes the body in a thread, returning immediately to the calling
528
+ thread. The body may do blocking I/O but must not do extended computation.
529
+ Returns a channel which will receive the result of the body when completed,
530
+ then close."
531
+ [& body]
532
+ `(thread-call (^:once fn* [] ~@body) :io ))
493
533
494
534
; ;;;;;;;;;;;;;;;;;;; ops ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
495
535
0 commit comments