11# This file is a part of Julia. License is MIT: https://julialang.org/license
22
3- export threadid, nthreads, @threads , @spawn
3+ export threadid, nthreads, @threads , @spawn ,
4+ threadpool, nthreadpools, nthreads_in_pool
45
56"""
6- Threads.threadid()
7+ Threads.threadid() -> Int
78
8- Get the ID number of the current thread of execution. The master thread has ID `1`.
9+ Get the ID number of the current thread of execution. The master thread has
10+ ID `1`.
911"""
1012threadid () = Int (ccall (:jl_threadid , Int16, ())+ 1 )
1113
12- # Inclusive upper bound on threadid()
1314"""
14- Threads.nthreads()
15+ Threads.nthreads() -> Int
1516
16- Get the number of threads available to the Julia process. This is the inclusive upper bound
17- on [`threadid()`](@ref).
17+ Get the number of threads (across all thread pools) available to the Julia
18+ process. This is the inclusive upper bound on [`threadid()`](@ref).
1819
1920See also: `BLAS.get_num_threads` and `BLAS.set_num_threads` in the
2021[`LinearAlgebra`](@ref man-linalg) standard library, and `nprocs()` in the
2122[`Distributed`](@ref man-distributed) standard library.
2223"""
2324nthreads () = Int (unsafe_load (cglobal (:jl_n_threads , Cint)))
2425
26+ """
27+ Threads.threadpool(tid = threadid()) -> Symbol
28+
29+ Returns the specified thread's threadpool; either `:default` or `:interactive`.
30+ """
31+ function threadpool (tid = threadid ())
32+ tpid = ccall (:jl_threadpoolid , Int8, (Int16,), tid- 1 )
33+ return tpid == 0 ? :default : :interactive
34+ end
35+
36+ """
37+ Threads.nthreadpools() -> Int
38+
39+ Returns the number of threadpools currently configured.
40+ """
41+ nthreadpools () = Int (unsafe_load (cglobal (:jl_n_threadpools , Cint)))
42+
43+ """
44+ Threads.nthreads_in_pool(pool::Symbol) -> Int
45+
46+ Returns the number of threads in the specified pool (`:default` or `:interactive`).
47+ """
48+ function nthreads_in_pool (pool:: Symbol )
49+ if pool == :default
50+ tpid = Int8 (0 )
51+ elseif pool == :interactive
52+ tpid = Int8 (1 )
53+ else
54+ error (" invalid threadpool specified" )
55+ end
56+ return _nthreads_in_pool (tpid)
57+ end
58+ function _nthreads_in_pool (tpid:: Int8 )
59+ p = unsafe_load (cglobal (:jl_n_threads_per_pool , Ptr{Cint}))
60+ return Int (unsafe_load (p, tpid + 1 ))
61+ end
62+
63+
2564function threading_run (fun, static)
2665 ccall (:jl_enter_threaded_region , Cvoid, ())
2766 n = nthreads ()
@@ -48,7 +87,7 @@ function _threadsfor(iter, lbody, schedule)
4887 quote
4988 local threadsfor_fun
5089 let range = $ (esc (range))
51- function threadsfor_fun (tid= 1 ; onethread= false )
90+ function threadsfor_fun (tid = 1 ; onethread = false )
5291 r = range # Load into local variable
5392 lenr = length (r)
5493 # divide loop iterations among threads
@@ -232,35 +271,63 @@ macro threads(args...)
232271end
233272
234273"""
235- Threads.@spawn expr
274+ Threads.@spawn [:default|:interactive] expr
236275
237- Create a [`Task`](@ref) and [`schedule`](@ref) it to run on any available thread.
238- The task is allocated to a thread after it becomes available. To wait for the task
239- to finish, call [`wait`](@ref) on the result of this macro, or call [`fetch`](@ref) to
240- wait and then obtain its return value.
276+ Create a [`Task`](@ref) and [`schedule`](@ref) it to run on any available
277+ thread in the specified threadpool (`:default` if unspecified). The task is
278+ allocated to a thread once one becomes available. To wait for the task to
279+ finish, call [`wait`](@ref) on the result of this macro, or call
280+ [`fetch`](@ref) to wait and then obtain its return value.
241281
242- Values can be interpolated into `@spawn` via `\$ `, which copies the value directly into the
243- constructed underlying closure. This allows you to insert the _value_ of a variable,
244- isolating the asynchronous code from changes to the variable's value in the current task.
282+ Values can be interpolated into `@spawn` via `\$ `, which copies the value
283+ directly into the constructed underlying closure. This allows you to insert
284+ the _value_ of a variable, isolating the asynchronous code from changes to
285+ the variable's value in the current task.
245286
246287!!! note
247- See the manual chapter on threading for important caveats.
288+ See the manual chapter on [multi-threading](@ref man-multi-threading)
289+ for important caveats. See also the chapter on [threadpools](@ref man-threadpools).
248290
249291!!! compat "Julia 1.3"
250292 This macro is available as of Julia 1.3.
251293
252294!!! compat "Julia 1.4"
253295 Interpolating values via `\$ ` is available as of Julia 1.4.
296+
297+ !!! compat "Julia 1.9"
298+ A threadpool may be specified as of Julia 1.9.
254299"""
255- macro spawn (expr)
256- letargs = Base. _lift_one_interp! (expr)
300+ macro spawn (args... )
301+ tpid = Int8 (0 )
302+ na = length (args)
303+ if na == 2
304+ ttype, ex = args
305+ if ttype isa QuoteNode
306+ ttype = ttype. value
307+ elseif ttype isa Symbol
308+ # TODO : allow unquoted symbols
309+ ttype = nothing
310+ end
311+ if ttype === :interactive
312+ tpid = Int8 (1 )
313+ elseif ttype != = :default
314+ throw (ArgumentError (" unsupported threadpool in @spawn: $ttype " ))
315+ end
316+ elseif na == 1
317+ ex = args[1 ]
318+ else
319+ throw (ArgumentError (" wrong number of arguments in @spawn" ))
320+ end
321+
322+ letargs = Base. _lift_one_interp! (ex)
257323
258- thunk = esc (:(()-> ($ expr )))
324+ thunk = esc (:(()-> ($ ex )))
259325 var = esc (Base. sync_varname)
260326 quote
261327 let $ (letargs... )
262328 local task = Task ($ thunk)
263329 task. sticky = false
330+ ccall (:jl_set_task_threadpoolid , Cint, (Any, Int8), task, $ tpid)
264331 if $ (Expr (:islocal , var))
265332 put! ($ var, task)
266333 end
0 commit comments