diff --git a/NEWS.md b/NEWS.md index 3aa74034ead54..796fe9647fff0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -29,6 +29,13 @@ New language features Language changes ---------------- + - Julia now defaults to 1 "interactive" thread, in addition to the 1 "default" worker thread. i.e. `-t1,1` + This means in default configuration the main task and repl (when in interactive mode), which both run on + thread 1, now run within the `interactive` threadpool. Also the libuv IO loop runs on thread 1, + helping efficient utilization of the "default" worker threadpool, which is what `Threads.@threads` and a bare + `Threads.@spawn` uses. Use `0` to disable the interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0`, or + `-tauto,0` etc. The zero is explicitly required to disable it, `-t2` will set the equivalent of `-t2,1` ([#57087]) + - When methods are replaced with exactly equivalent ones, the old method is no longer deleted implicitly simultaneously, although the new method does take priority and become more specific than the old method. Thus if the new diff --git a/base/channels.jl b/base/channels.jl index 527c22b3d45fd..ef508bd40e3ed 100644 --- a/base/channels.jl +++ b/base/channels.jl @@ -130,8 +130,7 @@ julia> chnl = Channel{Char}(1, spawn=true) do ch for c in "hello world" put!(ch, c) end - end -Channel{Char}(1) (2 items available) + end; julia> String(collect(chnl)) "hello world" diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index 2673ca7532acf..178a674e46643 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -941,7 +941,7 @@ While the streaming I/O API is synchronous, the underlying implementation is ful Consider the printed output from the following: -```jldoctest +``` julia> @sync for i in 1:3 Threads.@spawn write(stdout, string(i), " Foo ", " Bar ") end @@ -954,7 +954,7 @@ yields to other tasks while waiting for that part of the I/O to complete. `print` and `println` "lock" the stream during a call. Consequently changing `write` to `println` in the above example results in: -```jldoctest +``` julia> @sync for i in 1:3 Threads.@spawn println(stdout, string(i), " Foo ", " Bar ") end @@ -965,7 +965,7 @@ julia> @sync for i in 1:3 You can lock your writes with a `ReentrantLock` like this: -```jldoctest +``` julia> l = ReentrantLock(); julia> @sync for i in 1:3 diff --git a/doc/src/manual/methods.md b/doc/src/manual/methods.md index e448c62465b0d..45d22e08aaffe 100644 --- a/doc/src/manual/methods.md +++ b/doc/src/manual/methods.md @@ -615,7 +615,7 @@ Start some other operations that use `f(x)`: julia> g(x) = f(x) g (generic function with 1 method) -julia> t = Threads.@spawn f(wait()); yield(); +julia> t = @async f(wait()); yield(); ``` Now we add some new methods to `f(x)`: @@ -640,7 +640,7 @@ julia> g(1) julia> fetch(schedule(t, 1)) "original definition" -julia> t = Threads.@spawn f(wait()); yield(); +julia> t = @async f(wait()); yield(); julia> fetch(schedule(t, 1)) "definition for Int" diff --git a/doc/src/manual/multi-threading.md b/doc/src/manual/multi-threading.md index 209e2ffe1da56..ec470f867cc47 100644 --- a/doc/src/manual/multi-threading.md +++ b/doc/src/manual/multi-threading.md @@ -5,11 +5,13 @@ of Julia multi-threading features. ## Starting Julia with multiple threads -By default, Julia starts up with a single thread of execution. This can be verified by using the -command [`Threads.nthreads()`](@ref): +By default, Julia starts up with 2 threads of execution; 1 worker thread and 1 interactive thread. +This can be verified by using the command [`Threads.nthreads()`](@ref): ```jldoctest -julia> Threads.nthreads() +julia> Threads.nthreads(:default) +1 +julia> Threads.nthreads(:interactive) 1 ``` @@ -22,6 +24,9 @@ The number of threads can either be specified as an integer (`--threads=4`) or a (`--threads=auto`), where `auto` tries to infer a useful default number of threads to use (see [Command-line Options](@ref command-line-interface) for more details). +See [threadpools](@ref man-threadpools) for how to control how many `:default` and `:interactive` threads are in +each threadpool. + !!! compat "Julia 1.5" The `-t`/`--threads` command line argument requires at least Julia 1.5. In older versions you must use the environment variable instead. @@ -29,6 +34,10 @@ The number of threads can either be specified as an integer (`--threads=4`) or a !!! compat "Julia 1.7" Using `auto` as value of the environment variable [`JULIA_NUM_THREADS`](@ref JULIA_NUM_THREADS) requires at least Julia 1.7. In older versions, this value is ignored. + +!!! compat "Julia 1.12" + Starting by default with 1 interactive thread, as well as the 1 worker thread, was made as such in Julia 1.12 + Lets start Julia with 4 threads: ```bash @@ -96,10 +105,17 @@ using Base.Threads Interactive tasks should avoid performing high latency operations, and if they are long duration tasks, should yield frequently. -Julia may be started with one or more threads reserved to run interactive tasks: +By default Julia starts with one interactive thread reserved to run interactive tasks, but that number can +be controlled with: ```bash $ julia --threads 3,1 +julia> Threads.nthreads(:interactive) +1 + +$ julia --threads 3,0 +julia> Threads.nthreads(:interactive) +0 ``` The environment variable [`JULIA_NUM_THREADS`](@ref JULIA_NUM_THREADS) can also be used similarly: diff --git a/src/jloptions.c b/src/jloptions.c index 2c5a9074eb465..ac515bea19845 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -623,8 +623,13 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) break; case 't': // threads errno = 0; - jl_options.nthreadpools = 1; - long nthreads = -1, nthreadsi = 0; + jl_options.nthreadpools = 2; + // By default: + // default threads = -1 (== "auto") + long nthreads = -1; + // interactive threads = 1, or 0 if generating output + long nthreadsi = jl_generating_output() ? 0 : 1; + if (!strncmp(optarg, "auto", 4)) { jl_options.nthreads = -1; if (optarg[4] == ',') { @@ -633,10 +638,9 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) else { errno = 0; nthreadsi = strtol(&optarg[5], &endptr, 10); - if (errno != 0 || endptr == &optarg[5] || *endptr != 0 || nthreadsi < 1 || nthreadsi >= INT16_MAX) - jl_errorf("julia: -t,--threads=auto,; m must be an integer >= 1"); + if (errno != 0 || endptr == &optarg[5] || *endptr != 0 || nthreadsi < 0 || nthreadsi >= INT16_MAX) + jl_errorf("julia: -t,--threads=auto,; m must be an integer >= 0"); } - jl_options.nthreadpools++; } } else { @@ -650,17 +654,18 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) errno = 0; char *endptri; nthreadsi = strtol(&endptr[1], &endptri, 10); - if (errno != 0 || endptri == &endptr[1] || *endptri != 0 || nthreadsi < 1 || nthreadsi >= INT16_MAX) - jl_errorf("julia: -t,--threads=,; n and m must be integers >= 1"); + // Allow 0 for interactive + if (errno != 0 || endptri == &endptr[1] || *endptri != 0 || nthreadsi < 0 || nthreadsi >= INT16_MAX) + jl_errorf("julia: -t,--threads=,; m must be an integer ≥ 0"); + if (nthreadsi == 0) + jl_options.nthreadpools = 1; } - jl_options.nthreadpools++; } jl_options.nthreads = nthreads + nthreadsi; } int16_t *ntpp = (int16_t *)malloc_s(jl_options.nthreadpools * sizeof(int16_t)); ntpp[0] = (int16_t)nthreads; - if (jl_options.nthreadpools == 2) - ntpp[1] = (int16_t)nthreadsi; + ntpp[1] = (int16_t)nthreadsi; jl_options.nthreads_per_pool = ntpp; break; case 'p': // procs diff --git a/src/threading.c b/src/threading.c index ab63114fc9c8f..a51916cdcd8d8 100644 --- a/src/threading.c +++ b/src/threading.c @@ -698,15 +698,15 @@ void jl_init_threading(void) // and `jl_n_threads_per_pool`. jl_n_threadpools = 2; int16_t nthreads = JULIA_NUM_THREADS; - int16_t nthreadsi = 0; + // if generating output default to 0 interactive threads, otherwise default to 1 + int16_t nthreadsi = jl_generating_output() ? 0 : 1; char *endptr, *endptri; if (jl_options.nthreads != 0) { // --threads specified nthreads = jl_options.nthreads_per_pool[0]; if (nthreads < 0) nthreads = jl_effective_threads(); - if (jl_options.nthreadpools == 2) - nthreadsi = jl_options.nthreads_per_pool[1]; + nthreadsi = (jl_options.nthreadpools == 1) ? 0 : jl_options.nthreads_per_pool[1]; } else if ((cp = getenv(NUM_THREADS_NAME))) { // ENV[NUM_THREADS_NAME] specified if (!strncmp(cp, "auto", 4)) { @@ -722,13 +722,16 @@ void jl_init_threading(void) } if (*cp == ',') { cp++; - if (!strncmp(cp, "auto", 4)) + if (!strncmp(cp, "auto", 4)) { nthreadsi = 1; + cp += 4; + } else { errno = 0; nthreadsi = strtol(cp, &endptri, 10); if (errno != 0 || endptri == cp || nthreadsi < 0) - nthreadsi = 0; + nthreadsi = 1; + cp = endptri; } } } diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 2c8d48cc232cf..77d056b63655d 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -1187,7 +1187,7 @@ let s, c, r REPL.REPLCompletions.next_cache_update = 0 end c,r = test_scomplete(s) - wait(REPL.REPLCompletions.PATH_cache_task::Task) # wait for caching to complete + timedwait(()->REPL.REPLCompletions.next_cache_update != 0, 5) # wait for caching to complete c,r = test_scomplete(s) @test "tmp-executable" in c @test r == 1:9 @@ -1221,7 +1221,7 @@ let s, c, r REPL.REPLCompletions.next_cache_update = 0 end c,r = test_scomplete(s) - wait(REPL.REPLCompletions.PATH_cache_task::Task) # wait for caching to complete + timedwait(()->REPL.REPLCompletions.next_cache_update != 0, 5) # wait for caching to complete c,r = test_scomplete(s) @test ["repl-completion"] == c @test s[r] == "repl-completio" diff --git a/test/gcext/gcext-test.jl b/test/gcext/gcext-test.jl index 81637392e3c5d..86b6ad1a2ce59 100644 --- a/test/gcext/gcext-test.jl +++ b/test/gcext/gcext-test.jl @@ -31,7 +31,7 @@ end # @test success(p) errlines = fetch(err_task) lines = fetch(out_task) - @test length(errlines) == 0 + @test isempty(errlines) # @test length(lines) == 6 @test length(lines) == 5 @test checknum(lines[2], r"([0-9]+) full collections", n -> n >= 10) diff --git a/test/gcext/gcext.c b/test/gcext/gcext.c index d5bf91ec8c9ab..3da44a388a5b8 100644 --- a/test/gcext/gcext.c +++ b/test/gcext/gcext.c @@ -600,6 +600,13 @@ int main() jl_gc_set_cb_notify_external_alloc(alloc_bigval, 1); jl_gc_set_cb_notify_external_free(free_bigval, 1); + // single threaded mode + // Note: with -t1,1 a signal 10 occurs in task_scanner + jl_options.nthreadpools = 1; + jl_options.nthreads = 1; + int16_t ntpp[] = {jl_options.nthreads}; + jl_options.nthreads_per_pool = ntpp; + jl_init(); if (jl_gc_enable_conservative_gc_support() < 0) abort(); diff --git a/test/threads.jl b/test/threads.jl index 43fbea1e351a2..a1da408252fc4 100644 --- a/test/threads.jl +++ b/test/threads.jl @@ -72,11 +72,24 @@ let e = Event(true), started1 = Event(true), started2 = Event(true), done = Even end end -let cmd = `$(Base.julia_cmd()) --depwarn=error --rr-detach --startup-file=no threads_exec.jl` - for test_nthreads in (1, 2, 4, 4) # run once to try single-threaded mode, then try a couple times to trigger bad races + +let cmd1 = `$(Base.julia_cmd()) --depwarn=error --rr-detach --startup-file=no threads_exec.jl`, + cmd2 = `$(Base.julia_cmd()) --depwarn=error --rr-detach --startup-file=no -e 'print(Threads.threadpoolsize(:default), ",", Threads.threadpoolsize(:interactive))'` + for (test_nthreads, test_nthreadsi) in ( + (1, 0), + (1, 1), + (2, 0), + (2, 1), + (4, 0), + (4, 0)) # try a couple times to trigger bad races new_env = copy(ENV) - new_env["JULIA_NUM_THREADS"] = string(test_nthreads) - run(pipeline(setenv(cmd, new_env), stdout = stdout, stderr = stderr)) + new_env["JULIA_NUM_THREADS"] = string(test_nthreads, ",", test_nthreadsi) + run(pipeline(setenv(cmd1, new_env), stdout = stdout, stderr = stderr)) + threads_config = "$test_nthreads,$test_nthreadsi" + # threads set via env var + @test chomp(read(setenv(cmd2, new_env), String)) == threads_config + # threads set via -t + @test chomp(read(`$cmd2 -t$test_nthreads,$test_nthreadsi`, String)) == threads_config end end diff --git a/test/threads_exec.jl b/test/threads_exec.jl index 65e5ef57c911b..7091893908cb3 100644 --- a/test/threads_exec.jl +++ b/test/threads_exec.jl @@ -31,10 +31,11 @@ Timer(t -> killjob("KILLING BY THREAD TEST WATCHDOG\n"), 1200) @testset """threads_exec.jl with JULIA_NUM_THREADS == $(ENV["JULIA_NUM_THREADS"])""" begin @test Threads.threadid() == 1 -@test 1 <= threadpoolsize() <= Threads.maxthreadid() +@test threadpool() in (:interactive, :default) # thread 1 could be in the interactive pool +@test 1 <= threadpoolsize(:default) <= Threads.maxthreadid() # basic lock check -if threadpoolsize() > 1 +if threadpoolsize(:default) > 1 let lk = SpinLock() c1 = Base.Event() c2 = Base.Event() @@ -56,7 +57,18 @@ end # threading constructs -let a = zeros(Int, 2 * threadpoolsize()) +@testset "@threads and @spawn threadpools" begin + @threads for i in 1:1 + @test threadpool() == :default + end + @test fetch(Threads.@spawn threadpool()) == :default + @test fetch(Threads.@spawn :default threadpool()) == :default + if threadpoolsize(:interactive) > 0 + @test fetch(Threads.@spawn :interactive threadpool()) == :interactive + end +end + +let a = zeros(Int, 2 * threadpoolsize(:default)) @threads for i = 1:length(a) @sync begin @async begin @@ -76,7 +88,7 @@ end # parallel loop with parallel atomic addition function threaded_loop(a, r, x) - counter = Threads.Atomic{Int}(min(threadpoolsize(), length(r))) + counter = Threads.Atomic{Int}(min(threadpoolsize(:default), length(r))) @threads for i in r # synchronize the start given that each partition is started sequentially, # meaning that without the wait, if the loop is too fast the iteration can happen in order @@ -429,7 +441,7 @@ end for T in intersect((Int32, Int64, Float32, Float64), Base.Threads.atomictypes) var = Atomic{T}() nloops = 1000 - di = threadpoolsize() + di = threadpoolsize(:default) @threads for i in 1:di test_atomic_cas!(var, i:di:nloops) end @@ -519,13 +531,13 @@ function test_thread_cfunction() @test cfs[1] == cf1 @test cfs[2] == cf(fs[2]) @test length(unique(cfs)) == 1000 - ok = zeros(Int, threadpoolsize()) + ok = zeros(Int, threadpoolsize(:default)) @threads :static for i in 1:10000 i = mod1(i, 1000) fi = fs[i] cfi = cf(fi) GC.@preserve cfi begin - ok[threadid()] += (cfi === cfs[i]) + ok[threadid() - threadpoolsize(:interactive)] += (cfi === cfs[i]) end end @test sum(ok) == 10000 @@ -534,20 +546,6 @@ if cfunction_closure test_thread_cfunction() end -function test_thread_range() - a = zeros(Int, threadpoolsize()) - @threads for i in 1:threadid() - a[i] = 1 - end - for i in 1:threadid() - @test a[i] == 1 - end - for i in (threadid() + 1):threadpoolsize() - @test a[i] == 0 - end -end -test_thread_range() - # Thread safety of `jl_load_and_lookup`. function test_load_and_lookup_18020(n) @threads for i in 1:n @@ -582,17 +580,17 @@ test_nested_loops() function test_thread_too_few_iters() x = Atomic() - a = zeros(Int, threadpoolsize()+2) - threaded_loop(a, 1:threadpoolsize()-1, x) - found = zeros(Bool, threadpoolsize()+2) - for i=1:threadpoolsize()-1 + a = zeros(Int, threadpoolsize(:default)+2) + threaded_loop(a, 1:threadpoolsize(:default)-1, x) + found = zeros(Bool, threadpoolsize(:default)+2) + for i=1:threadpoolsize(:default)-1 found[a[i]] = true end - @test x[] == threadpoolsize()-1 + @test x[] == threadpoolsize(:default)-1 # Next test checks that all loop iterations ran, # and were unique (via pigeon-hole principle). - @test !(false in found[1:threadpoolsize()-1]) - @test !(true in found[threadpoolsize():end]) + @test !(false in found[1:threadpoolsize(:default)-1]) + @test !(true in found[threadpoolsize(:default):end]) end test_thread_too_few_iters() @@ -734,10 +732,10 @@ function _atthreads_with_error(a, err) end a end -@test_throws CompositeException _atthreads_with_error(zeros(threadpoolsize()), true) -let a = zeros(threadpoolsize()) +@test_throws CompositeException _atthreads_with_error(zeros(threadpoolsize(:default)), true) +let a = zeros(threadpoolsize(:default)) _atthreads_with_error(a, false) - @test a == [1:threadpoolsize();] + @test a == [threadpoolsize(:interactive) .+ (1:threadpoolsize(:default));] end # static schedule @@ -748,11 +746,11 @@ function _atthreads_static_schedule(n) end return ids end -@test _atthreads_static_schedule(threadpoolsize()) == 1:threadpoolsize() -@test _atthreads_static_schedule(1) == [1;] +@test _atthreads_static_schedule(threadpoolsize(:default)) == threadpoolsize(:interactive) .+ (1:threadpoolsize(:default)) +@test _atthreads_static_schedule(1) == [threadpoolsize(:interactive) + 1;] @test_throws( "`@threads :static` cannot be used concurrently or nested", - @threads(for i = 1:1; _atthreads_static_schedule(threadpoolsize()); end), + @threads(for i = 1:1; _atthreads_static_schedule(threadpoolsize(:default)); end), ) # dynamic schedule @@ -765,35 +763,35 @@ function _atthreads_dynamic_schedule(n) end return inc[], flags end -@test _atthreads_dynamic_schedule(threadpoolsize()) == (threadpoolsize(), ones(threadpoolsize())) +@test _atthreads_dynamic_schedule(threadpoolsize(:default)) == (threadpoolsize(:default), ones(threadpoolsize(:default))) @test _atthreads_dynamic_schedule(1) == (1, ones(1)) @test _atthreads_dynamic_schedule(10) == (10, ones(10)) -@test _atthreads_dynamic_schedule(threadpoolsize() * 2) == (threadpoolsize() * 2, ones(threadpoolsize() * 2)) +@test _atthreads_dynamic_schedule(threadpoolsize(:default) * 2) == (threadpoolsize(:default) * 2, ones(threadpoolsize(:default) * 2)) # nested dynamic schedule function _atthreads_dynamic_dynamic_schedule() inc = Threads.Atomic{Int}(0) - Threads.@threads :dynamic for _ = 1:threadpoolsize() - Threads.@threads :dynamic for _ = 1:threadpoolsize() + Threads.@threads :dynamic for _ = 1:threadpoolsize(:default) + Threads.@threads :dynamic for _ = 1:threadpoolsize(:default) Threads.atomic_add!(inc, 1) end end return inc[] end -@test _atthreads_dynamic_dynamic_schedule() == threadpoolsize() * threadpoolsize() +@test _atthreads_dynamic_dynamic_schedule() == threadpoolsize(:default) * threadpoolsize(:default) function _atthreads_static_dynamic_schedule() - ids = zeros(Int, threadpoolsize()) + ids = zeros(Int, threadpoolsize(:default)) inc = Threads.Atomic{Int}(0) - Threads.@threads :static for i = 1:threadpoolsize() + Threads.@threads :static for i = 1:threadpoolsize(:default) ids[i] = Threads.threadid() - Threads.@threads :dynamic for _ = 1:threadpoolsize() + Threads.@threads :dynamic for _ = 1:threadpoolsize(:default) Threads.atomic_add!(inc, 1) end end return ids, inc[] end -@test _atthreads_static_dynamic_schedule() == (1:threadpoolsize(), threadpoolsize() * threadpoolsize()) +@test _atthreads_static_dynamic_schedule() == (threadpoolsize(:interactive) .+ (1:threadpoolsize(:default)), threadpoolsize(:default) * threadpoolsize(:default)) # errors inside @threads :dynamic function _atthreads_dynamic_with_error(a) @@ -802,7 +800,7 @@ function _atthreads_dynamic_with_error(a) end a end -@test_throws "user error in the loop body" _atthreads_dynamic_with_error(zeros(threadpoolsize())) +@test_throws "user error in the loop body" _atthreads_dynamic_with_error(zeros(threadpoolsize(:default))) #### # :greedy @@ -817,57 +815,57 @@ function _atthreads_greedy_schedule(n) end return inc[], flags end -@test _atthreads_greedy_schedule(threadpoolsize()) == (threadpoolsize(), ones(threadpoolsize())) +@test _atthreads_greedy_schedule(threadpoolsize(:default)) == (threadpoolsize(:default), ones(threadpoolsize(:default))) @test _atthreads_greedy_schedule(1) == (1, ones(1)) @test _atthreads_greedy_schedule(10) == (10, ones(10)) -@test _atthreads_greedy_schedule(threadpoolsize() * 2) == (threadpoolsize() * 2, ones(threadpoolsize() * 2)) +@test _atthreads_greedy_schedule(threadpoolsize(:default) * 2) == (threadpoolsize(:default) * 2, ones(threadpoolsize(:default) * 2)) # nested greedy schedule function _atthreads_greedy_greedy_schedule() inc = Threads.Atomic{Int}(0) - Threads.@threads :greedy for _ = 1:threadpoolsize() - Threads.@threads :greedy for _ = 1:threadpoolsize() + Threads.@threads :greedy for _ = 1:threadpoolsize(:default) + Threads.@threads :greedy for _ = 1:threadpoolsize(:default) Threads.atomic_add!(inc, 1) end end return inc[] end -@test _atthreads_greedy_greedy_schedule() == threadpoolsize() * threadpoolsize() +@test _atthreads_greedy_greedy_schedule() == threadpoolsize(:default) * threadpoolsize(:default) function _atthreads_greedy_dynamic_schedule() inc = Threads.Atomic{Int}(0) - Threads.@threads :greedy for _ = 1:threadpoolsize() - Threads.@threads :dynamic for _ = 1:threadpoolsize() + Threads.@threads :greedy for _ = 1:threadpoolsize(:default) + Threads.@threads :dynamic for _ = 1:threadpoolsize(:default) Threads.atomic_add!(inc, 1) end end return inc[] end -@test _atthreads_greedy_dynamic_schedule() == threadpoolsize() * threadpoolsize() +@test _atthreads_greedy_dynamic_schedule() == threadpoolsize(:default) * threadpoolsize(:default) function _atthreads_dymamic_greedy_schedule() inc = Threads.Atomic{Int}(0) - Threads.@threads :dynamic for _ = 1:threadpoolsize() - Threads.@threads :greedy for _ = 1:threadpoolsize() + Threads.@threads :dynamic for _ = 1:threadpoolsize(:default) + Threads.@threads :greedy for _ = 1:threadpoolsize(:default) Threads.atomic_add!(inc, 1) end end return inc[] end -@test _atthreads_dymamic_greedy_schedule() == threadpoolsize() * threadpoolsize() +@test _atthreads_dymamic_greedy_schedule() == threadpoolsize(:default) * threadpoolsize(:default) function _atthreads_static_greedy_schedule() - ids = zeros(Int, threadpoolsize()) + ids = zeros(Int, threadpoolsize(:default)) inc = Threads.Atomic{Int}(0) - Threads.@threads :static for i = 1:threadpoolsize() + Threads.@threads :static for i = 1:threadpoolsize(:default) ids[i] = Threads.threadid() - Threads.@threads :greedy for _ = 1:threadpoolsize() + Threads.@threads :greedy for _ = 1:threadpoolsize(:default) Threads.atomic_add!(inc, 1) end end return ids, inc[] end -@test _atthreads_static_greedy_schedule() == (1:threadpoolsize(), threadpoolsize() * threadpoolsize()) +@test _atthreads_static_greedy_schedule() == (threadpoolsize(:interactive) .+ (1:threadpoolsize(:default)), threadpoolsize(:default) * threadpoolsize(:default)) # errors inside @threads :greedy function _atthreads_greedy_with_error(a) @@ -876,7 +874,7 @@ function _atthreads_greedy_with_error(a) end a end -@test_throws "user error in the loop body" _atthreads_greedy_with_error(zeros(threadpoolsize())) +@test_throws "user error in the loop body" _atthreads_greedy_with_error(zeros(threadpoolsize(:default))) #### # multi-argument loop @@ -1109,7 +1107,7 @@ function check_sync_end_race() nnotscheduled += y === :notscheduled end # Useful for tuning the test: - @debug "`check_sync_end_race` done" threadpoolsize() ncompleted nnotscheduled nerror + @debug "`check_sync_end_race` done" threadpoolsize(:default) ncompleted nnotscheduled nerror finally done[] = true end @@ -1123,7 +1121,7 @@ end # issue #41546, thread-safe package loading @testset "package loading" begin - ntasks = max(threadpoolsize(), 4) + ntasks = max(threadpoolsize(:default), 4) ch = Channel{Bool}(ntasks) barrier = Base.Event() old_act_proj = Base.ACTIVE_PROJECT[]