Spinner/progress meter for slow functions

I am aware of the package ProgressMeter.jl which works for function which process things in loops. I am looking for something that works on functions that doesn’t necessarily have loop but just takes time to complete some complex calculation. Also, because there is no loop per se, so I am not expecting to display a progress meter, but simply a spinner would work just fine till the function is done executing.

1 Like

See the ProgressMeter manual section on tasks with an unknown number of steps, which is precisely for your sort of problem, and includes spinner options.

1 Like

Thanks @stevengj. This is precisely what I tried but for this to work I still need some sort of loop. My code looks something like this:

function slow_function()
    sleep(10) #emulating complex calculation
end

function run()
    # progress/spinner display
    slow_function() #while this executes I display the spinner
   return
end

run()

Here, I don’t have any loop (so the ProgressUnknown function would still not work). Please let me know if I am missing something here and could somehow still use the ProgressMeter.jl package. Thanks!

Yes, that didn’t work. Again because there is no loop at all.

Yeah I realized it won’t work :frowning:

Looking at stevengj’s link, the examples show a loop because the next! call can occur gracefully at one point in each iteration, but you can also call next! in several places in your method. Reading the rest of the README, it looks like next! also works on progress types with a known number of steps, and this seems preferable because you manually determine how many times next! is called.

I don’t think progress indication can occur independently of the method. The @showprogress macro transforms expressions to include steps indicating the progress. Hypothetically you could run a timer totally independently of the method, but it cannot know where the method is when it reports a time, so it cannot serve as a progress indicator. I think it would have to look like:

function slow_progress()
   p = Progress(2; dt=1.0) # only call 2 times
   # do some stuff
   next!(p)
   # do more stuff
   next!(p)
   return
end

Ideally you space it out so you’re doing about the same amount of work between next! calls, so the progress increments mostly smoothly; that occurs often in loops of course. The update! function could be better if the amount of work varies quantifiably and can be worked into the increment.

1 Like

This makes sense. The only problem is that slow_function is imported from a different package and I have no control over it (in terms of modifying it). I assume there is no other way so far. But thanks for the reasoning behind next!, I can at least use it in functions written by me. Thanks!

That’s unfortunate. Since the method doesn’t indicate its progress or some measure of how close it is to ending, the best you can do is log how long each call takes and report the statistics prior to the next calls. If runtime varies over input size in a predictable way (like a bigger file or more files), you could model it. Hopefully the model was accurate enough to be a good predictor with enough data. None of the timing statistics tells you about the progress, just like how progress can’t tell you how long any increment would take, but at least you have nonzero information about how long your lunchbreak can be.

1 Like

That’s a nice workaround. Also, I am not really interested in showing the exact progress. I understand it can vary based on the input and difficult to track in this case. Hence, I am looking more at some sort of spinner that can be displayed (may be rotate every one second) while the function runs and stops once the function is executed. I can use your idea of average statistics to display beside the rotating spinner. The whole idea is to not make the screen look as if it’s stuck and not doing anything.

Something like this should work:

using ProgressMeter

slow_function() = sleep(10)

p = ProgressUnknown(; spinner=true)
channel = Channel() do ch
    while !isready(ch)
        next!(p)
        sleep(1)
    end
end;
slow_function()
close(channel)

It just spawns a thread to spin the progress meter every second and then stops it (by closing the channel) once the function has returned.

4 Likes

This is great! Thanks. However the progress meter keeps running even after the close(channel).

Oops!

Try this instead:

using ProgressMeter

slow_function() = sleep(3)

p = ProgressUnknown(; spinner=true)
channel = Channel() do ch
    while !isready(ch)
        next!(p)
        sleep(1)
    end
    take!(ch)
end;
slow_function()
put!(channel, 1)
6 Likes

Perfect! Thanks!