Skip to content

Commit 50b82ce

Browse files
committed
remove incorrect examples about thread-unsafe functions in docs (#33419)
* remove incorrect examples about thread unsafe functions * Delete my_file.txt
1 parent 4dfffb6 commit 50b82ce

File tree

1 file changed

+1
-89
lines changed

1 file changed

+1
-89
lines changed

doc/src/manual/parallel-computing.md

Lines changed: 1 addition & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -396,95 +396,7 @@ When using multi-threading we have to be careful when using functions that are n
396396
For instance functions that have their
397397
[name ending with `!`](https://docs.julialang.org/en/latest/manual/style-guide/#Append-!-to-names-of-functions-that-modify-their-arguments-1)
398398
by convention modify their arguments and thus are not pure. However, there are
399-
functions that have side effects and their name does not end with `!`. For
400-
instance [`findfirst(regex, str)`](@ref) mutates its `regex` argument or
401-
[`rand()`](@ref) changes `Base.GLOBAL_RNG` :
402-
403-
```julia-repl
404-
julia> using Base.Threads
405-
406-
julia> nthreads()
407-
4
408-
409-
julia> function f()
410-
s = repeat(["123", "213", "231"], outer=1000)
411-
x = similar(s, Int)
412-
rx = r"1"
413-
@threads for i in 1:3000
414-
x[i] = findfirst(rx, s[i]).start
415-
end
416-
count(v -> v == 1, x)
417-
end
418-
f (generic function with 1 method)
419-
420-
julia> f() # the correct result is 1000
421-
1017
422-
423-
julia> function g()
424-
a = zeros(1000)
425-
@threads for i in 1:1000
426-
a[i] = rand()
427-
end
428-
length(unique(a))
429-
end
430-
g (generic function with 1 method)
431-
432-
julia> Random.seed!(1); g() # the result for a single thread is 1000
433-
781
434-
```
435-
436-
In such cases one should redesign the code to avoid the possibility of a race condition or use
437-
[synchronization primitives](https://docs.julialang.org/en/latest/base/multi-threading/#Synchronization-Primitives-1).
438-
439-
For example in order to fix `findfirst` example above one needs to have a
440-
separate copy of `rx` variable for each thread:
441-
442-
```julia-repl
443-
julia> function f_fix()
444-
s = repeat(["123", "213", "231"], outer=1000)
445-
x = similar(s, Int)
446-
rx = [Regex("1") for i in 1:nthreads()]
447-
@threads for i in 1:3000
448-
x[i] = findfirst(rx[threadid()], s[i]).start
449-
end
450-
count(v -> v == 1, x)
451-
end
452-
f_fix (generic function with 1 method)
453-
454-
julia> f_fix()
455-
1000
456-
```
457-
458-
We now use `Regex("1")` instead of `r"1"` to make sure that Julia
459-
creates separate instances of `Regex` object for each entry of `rx` vector.
460-
461-
The case of `rand` is a bit more complex as we have to ensure that each thread
462-
uses non-overlapping pseudorandom number sequences. This can be simply ensured
463-
by using `Future.randjump` function:
464-
465-
466-
```julia-repl
467-
julia> using Random; import Future
468-
469-
julia> function g_fix(r)
470-
a = zeros(1000)
471-
@threads for i in 1:1000
472-
a[i] = rand(r[threadid()])
473-
end
474-
length(unique(a))
475-
end
476-
g_fix (generic function with 1 method)
477-
478-
julia> r = let m = MersenneTwister(1)
479-
[m; accumulate(Future.randjump, fill(big(10)^20, nthreads()-1), init=m)]
480-
end;
481-
482-
julia> g_fix(r)
483-
1000
484-
```
485-
486-
We pass the `r` vector to `g_fix` as generating several RGNs is an expensive
487-
operation so we do not want to repeat it every time we run the function.
399+
functions that have side effects and their name does not end with `!`.
488400

489401
## @threadcall (Experimental)
490402

0 commit comments

Comments
 (0)