Search code examples
luasleepbusy-waitingtail-call

Why does my tail calling function not pause and flush output?


I have looked through lua-users Sleep Function reference in an effort to find a non-busy waiting solution to the sleep problem and I'm not happy with any of them. Nonetheless I attempted using several to provide a delay at the end of a function that uses tail calls.

Normally I wouldn't use tail calls but since lua doesn't leave a stack behind for tail calls it suits me.

Unfortunately I see my processor spike to about 20% use and the program becomes immediately unresponsive without any flushing of output once it begins.

The problem (simplified) looks like this:

function myFunc ()
   -- do some stuff
   -- lots of snazzy logic and function calls
   -- heck, throw in a few prints
   print "Going to sleep"
   -- sleep for a bit
   os.execute("sleep 10")
   print "Waking up"
   -- tail call
   return myFunc()
end

I have tried the socket select method, os.execute and of course busy waiting. Of these only busy waiting gives the expected behaviour.

Are these other non-busy waiting solutions also non blocking? That is do they allow the tail call to be processed despite the delays?

How can I flush the output and have the function wait 10 seconds before resuming without busy waiting?


Solution

  • On the advice of Nick Gammon I tried his wait.lua solution. My initial attempt:

    function controlLoop()
       wait.make (
          function()
             world.Note("Hello world.") -- essentially print
            wait.time(10)
         end
       )
       world.Note("Goodbye world.") -- essentially print
      return controlLoop()
    end
    

    Suffered from precisely the same 100% CPU use, no output displayed behaviour.

    My second attempt:

    function controlLoop()
       wait.make (
          function()
             world.Note("Hello world.")
             wait.time(10)
             world.Note("Goodbye world.")
             return controlLoop()
          end
       )
    end
    

    Has been running for 3 hours without fault. I did put a debug call to the stack trace using debug.traceback() and never got a response more than 1 level deep. Additionally watching the Window memory use for the process, it did not increase over the 3 hours.

    I am pleased that I have a solution but I am still somewhat displeased that I don't understand why it is working and why the original version fails.

    It has been pointed out to me that I'm suffering from tunnel vision and that a while loop will solve my problem famously.

    function controlLoop()
       wait.make (
          function()
             while true do
                world.Note("Hello world.")
                wait.time(10)
                world.Note("Goodbye world.")
             end -- loop
          end
       )
    end
    

    To which I can only reply ... duh, of course.