Giter Club home page Giter Club logo

threadtools.jl's Introduction

Build Status codecov

ThreadTools

This package implements some utilities for using threads in Julia v1.3+

The utilities provided are:

@spawnatmost n for i in ...

Spawn at most n threads to carry out for-loop

tmap(f, args...)
tmap(f, nthreads::Int, args...)
tmap1(f, args...)
tmap1(f, nthreads::Int,args...)

Threaded map. The optional argument nthreads limits the number of threads used in parallel. tmap1 is the same as tmap, but falls back to a regular map if julia only has access to one thread.

The tools to limit the number of threads used are useful when doing, e.g., threaded IO, where the disk might get overloaded if you try to access it from too many threads at the same time.

Examples

using ThreadTools

julia> l = SpinLock();
julia> times = [];
julia> @spawnatmost 3 for i = 1:10 # This will use only three parallel threads, even if more are avilable
            lock(l) do # We protect the access to the array using a lock
                push!(times, time())
            end
            println(i)
            sleep(1)
       end

julia> round.(diff(times), digits=2)
9-element Array{Float64,1}:
    0.0
    0.0
    1.0
    0.0
    0.0
    1.0
    0.0
    0.0
    1.0

julia> tmap(_->threadid(), 1:5) # A threaded version of map
5-element Array{Int64,1}:
 2
 6
 3
 4
 5

 julia> times = tmap(_->(t=time();sleep(0.3);t), 3, 1:10); # The second argument limits the number of threads used
 julia> round.(diff(times), digits=2)
 9-element Array{Float64,1}:
  0.0
  0.0
  0.3
  0.0
  0.0
  0.3
  0.0
  0.0
  0.3

Benchmark

All benchmarks are done on a machine with 6 physical cores. The following function will be used for benchmarking

function fib(n)
    if n <= 1 return 1 end
    return fib(n - 1) + fib(n - 2)
end

Light workload

fib(20) 720 times

workload = fill(20, factorial(6))
times = map(1:6) do nt
    nt == 1 && return @belapsed map(fib, workload)
    @belapsed tmap(fib, $nt, workload)
end
t720 = @belapsed tmap(fib, workload)
plot(1:6, times, xlabel="Number of threads", ylabel="Time [s]")
hline!([t720], label="720 tasks", ylims=(0,Inf))

window

Conclusion: for light loads, the overhead is large. You may want to consider KissThreading.jl for a more advanced approach.

Heavy workload

fib(30) 720 times

workload = fill(30, factorial(6))
times = map(1:6) do nt
    nt == 1 && return @belapsed map(fib, workload)
    @belapsed tmap(fib, $nt, workload)
end
t720 = @belapsed tmap(fib, workload)
plot(1:6, times, xlabel="Number of threads", ylabel="Time [s]")
hline!([t720], label="720 tasks", ylims=(0,Inf))

window

Conclusion: tmap is effective when the computational load is heavy.

threadtools.jl's People

Contributors

baggepinnen avatar juliatagbot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

threadtools.jl's Issues

Package fails on 1.5

Seems to be the removal of one of the internal sync_end methods.

ThreadTools: Error During Test at /home/pkgeval/.julia/packages/ThreadTools/5hMgn/test/runtests.jl:5
  Got exception outside of a @test
  MethodError: no method matching sync_end(::Array{Task,1})
  Closest candidates are:
    sync_end(!Matched::Channel{Any}) at task.jl:289
  Stacktrace:
   [1] macro expansion at /home/pkgeval/.julia/packages/ThreadTools/5hMgn/src/ThreadTools.jl:29 [inlined]
   [2] macro expansion at /home/pkgeval/.julia/packages/ThreadTools/5hMgn/test/runtests.jl:9 [inlined]
   [3] macro expansion at /workspace/srcdir/usr/share/julia/stdlib/v1.5/Test/src/Test.jl:1114 [inlined]
   [4] top-level scope at /home/pkgeval/.julia/packages/ThreadTools/5hMgn/test/runtests.jl:6
   [5] include(::String) at ./client.jl:457
   [6] top-level scope at none:6
   [7] eval(::Module, ::Any) at ./boot.jl:331
   [8] exec_options(::Base.JLOptions) at ./client.jl:272
   [9] _start() at ./client.jl:506

how to exit gracefully?

Whenever I Ctrl+C during a tmap call Julia crashes.

fatal: error thrown and no exception handler available.
InterruptException()
sigatomic_end at ./c.jl:425 [inlined]
task_done_hook at ./task.jl:440
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2214 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2398
jl_apply at /buildworker/worker/package_linux64/build/src/julia.h:1690 [inlined]
jl_finish_task at /buildworker/worker/package_linux64/build/src/task.c:198
start_task at /buildworker/worker/package_linux64/build/src/task.c:717
unknown function (ip: (nil))

Feature request: one thread per block

Dear BaggePinnen,

in https://discourse.julialang.org/t/regular-expression-and-threads/31415/4 I was testing a multi-threading performance of Regexp library. I have tried tmap, but since it executes one thread per item, it is kind of wasteful. I have therefore divided the work to blocks as

function getrange(n, tid = Threads.threadid(), nt = Threads.nthreads())
    d , r = divrem(n, nt)
    from = (tid - 1) * d + min(r, tid - 1) + 1
    to = from + d - 1 + (tid ≤ r ? 1 : 0)
    from:to
end

reduce(vcat, tmap(i -> map(f, items), [getrange(length(items), i) for i in 1:Threads.nthreads()]));

and the improvement in terms of time was massive. What do you think about adding this into your library?

Something along lines

function tmap(f, list; blockmode = false)
	if blockmode
		blocks = [getrange(length(urls), i) for i in 1:Threads.nthreads()]
		return(reduce(vcat, tmap(i -> map(is_valid_path, list[i]), blocks; blockmode = false)))
	else
		tasks = map(list) do l
        Threads.@spawn f(l)
	    return(fetch.(tasks))
    end
end

We would need to make it more general for multiple arguments.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.