@@ -38,7 +38,7 @@ function threading_run(func)
38
38
end
39
39
end
40
40
41
- function _threadsfor (iter,lbody)
41
+ function _threadsfor (iter, lbody, schedule )
42
42
lidx = iter. args[1 ] # index
43
43
range = iter. args[2 ]
44
44
quote
@@ -82,9 +82,13 @@ function _threadsfor(iter,lbody)
82
82
end
83
83
end
84
84
end
85
- if threadid () != 1
86
- # only thread 1 can enter/exit _threadedregion
87
- Base. invokelatest (threadsfor_fun, true )
85
+ if threadid () != 1 || ccall (:jl_in_threaded_region , Cint, ()) != 0
86
+ $ (if schedule === :static
87
+ :(error (" `@threads :static` can only be used from thread 1 and not nested" ))
88
+ else
89
+ # only use threads when called from thread 1, outside @threads
90
+ :(Base. invokelatest (threadsfor_fun, true ))
91
+ end )
88
92
else
89
93
threading_run (threadsfor_fun)
90
94
end
@@ -93,31 +97,50 @@ function _threadsfor(iter,lbody)
93
97
end
94
98
95
99
"""
96
- Threads.@threads
100
+ Threads.@threads [schedule] for ... end
97
101
98
- A macro to parallelize a for-loop to run with multiple threads. This spawns [`nthreads()`](@ref)
99
- number of threads, splits the iteration space amongst them, and iterates in parallel.
100
- A barrier is placed at the end of the loop which waits for all the threads to finish
101
- execution, and the loop returns.
102
+ A macro to parallelize a `for` loop to run with multiple threads. Splits the iteration
103
+ space among multiple tasks and runs those tasks on threads according to a scheduling
104
+ policy.
105
+ A barrier is placed at the end of the loop which waits for all tasks to finish
106
+ execution.
107
+
108
+ The `schedule` argument can be used to request a particular scheduling policy.
109
+ The only currently supported value is `:static`, which creates one task per thread
110
+ and divides the iterations equally among them. Specifying `:static` is an error
111
+ if used from inside another `@threads` loop or from a thread other than 1.
112
+
113
+ The default schedule (used when no `schedule` argument is present) is subject to change.
114
+
115
+ !!! compat "Julia 1.5"
116
+ The `schedule` argument is available as of Julia 1.5.
102
117
"""
103
118
macro threads (args... )
104
119
na = length (args)
105
- if na != 1
120
+ if na == 2
121
+ sched, ex = args
122
+ if sched isa QuoteNode
123
+ sched = sched. value
124
+ elseif sched isa Symbol
125
+ # for now only allow quoted symbols
126
+ sched = nothing
127
+ end
128
+ if sched != = :static
129
+ throw (ArgumentError (" unsupported schedule argument in @threads" ))
130
+ end
131
+ elseif na == 1
132
+ sched = :default
133
+ ex = args[1 ]
134
+ else
106
135
throw (ArgumentError (" wrong number of arguments in @threads" ))
107
136
end
108
- ex = args[1 ]
109
- if ! isa (ex, Expr)
110
- throw (ArgumentError (" need an expression argument to @threads" ))
137
+ if ! (isa (ex, Expr) && ex. head === :for )
138
+ throw (ArgumentError (" @threads requires a `for` loop expression" ))
111
139
end
112
- if ex. head === :for
113
- if ex. args[1 ] isa Expr && ex. args[1 ]. head === :(= )
114
- return _threadsfor (ex. args[1 ], ex. args[2 ])
115
- else
116
- throw (ArgumentError (" nested outer loops are not currently supported by @threads" ))
117
- end
118
- else
119
- throw (ArgumentError (" unrecognized argument to @threads" ))
140
+ if ! (ex. args[1 ] isa Expr && ex. args[1 ]. head === :(= ))
141
+ throw (ArgumentError (" nested outer loops are not currently supported by @threads" ))
120
142
end
143
+ return _threadsfor (ex. args[1 ], ex. args[2 ], sched)
121
144
end
122
145
123
146
"""
0 commit comments