Optional macro invocation

I suppose one fundamental distinction is whether you want to make the threads optional at runtime vs at compile time. I think you (and the OP) were primarily looking for a compile-time switch, whereas I’m looking for a runtime switch.

Based on @jlapeyre’s answer, it occurred to me that maybe the easiest way to do this for @threads is to just modify the definition of the macro from the standard library. Indeed, the following seems like it works perfectly for me:

module ConditionalThreads

using Base.Threads
using Base.Threads: threadid, threading_run

macro threadsif(cond, loop)
    if !(isa(loop, Expr) && loop.head === :for)
        throw(ArgumentError("@threadsif requires a `for` loop expression"))
    if !(loop.args[1] isa Expr && loop.args[1].head === :(=))
        throw(ArgumentError("nested outer loops are not currently supported by @threadsif"))
        if $(esc(cond))
            $(Threads._threadsfor(loop.args[1], loop.args[2], :static))


I’ve left out the schedule from the original implementation for conciseness since that’s currently limited to :static anyway. It wouldn’t be hard to add that back in.

Edit (usage example):

I currently have the above macro definition “in production” at QuantumControlBase.jl, and it is used e.g. here:

1 Like

version 2 of my maybethread macro above, which optionally threads at compile time, is now hygienic:

macro maybethread(loop)
  if use_threads
    quote Threads.@threads $(Expr(loop.head,
                             Expr(loop.args[1].head, esc.(loop.args[1].args)...),
                             esc(loop.args[2]))); end
    # @warn "running single threaded"
    quote $(esc(loop)); end

i typically define use_threads = Threads.nthreads()>1.

thanks @chakravala for your post which showed me how to do this.

figuring this out took a long time. maybe i’m stupid. maybe macros are hard. but i wholeheartedly agree with @Chris_Foster that we should rethink them for julia 2.0.