cory
cory

Reputation: 6659

How do I run a function every second

I want to run a function that takes less than one second to execute. I want to run it in a loop every second. I do not want to wait one second between running the function like Sys.sleep would do.

while(TRUE){
  # my function that takes less than a second to run
  Sys.sleep(runif(1, min=0, max=.8))  

  # wait for the remaining time until the next execution...
  # something here
}

I could record a starttime <- Sys.time() and do a comparison every iteration through the loop, something like this...

starttime <- Sys.time()
while(TRUE){
  if(abs(as.numeric(Sys.time() - starttime) %% 1) < .001){
    # my function that takes less than a second to run
    Sys.sleep(runif(1, min=0, max=.8))  
    print(paste("it ran", Sys.time()))
  }
}

But my function never seems to be executed.

I know python has a package to do this sort of thing. Does R also have one that I don't know about? Thanks.

Upvotes: 13

Views: 12091

Answers (5)

ismirsehregal
ismirsehregal

Reputation: 33442

Another non-blocking alternative worth mentioning is provided by library(later), via using later() recursive:

print_time = function(interval = 10) {
  timestamp()
  later::later(print_time, interval)
}

print_time()

The example is taken from here.

Upvotes: 3

G. Grothendieck
G. Grothendieck

Reputation: 269694

Here are some alternatives. These do not block. That is you can still use the console to run other code while they are running.

1) tcltk Try after in the tcltk package:

library(tcltk)

run <- function () { 
  .id <<- tcl("after", 1000, run) # after 1000 ms execute run() again
  cat(as.character(.id), "\n")    # replace with your code
}

run()

Running this on a fresh R session gives:

after#0 
after#1 
after#2 
after#3 
after#4 
after#5 
after#6 
after#7 
...etc...

To stop it tcl("after", "cancel", .id) .

2) tcltk2 Another possibility is tclTaskSchedule in the tcltk2 package:

library(tcltk2)

test <- function() cat("Hello\n")  # replace with your function
tclTaskSchedule(1000, test(), id = "test", redo = TRUE)

Stop it with:

tclTaskDelete("test")

or redo= can specify the number of times it should run.

Upvotes: 12

Varn K
Varn K

Reputation: 400

Although its very late.

As an alternative we can use recursion. I don't know if its the solution you are looking for. But it executes function at regular interval.

ssc <-  function(){
x <- rnorm(30,20,2)
print(hist(x))
 Sys.sleep(4)

 ssc()

 }
ssc()

Upvotes: 1

Se&#241;or O
Se&#241;or O

Reputation: 17412

You can keep track of the time with system.time

while(TRUE)
{
    s = system.time(Sys.sleep(runif(1, min = 0, max = 0.8)))
    Sys.sleep(1 - s[3]) #basically sleep for whatever is left of the second
}

You can also use proc.time directly (which system.time calls), which for some reasons got better results for me:

> system.time(
  for(i in 1:10)
  {
    p1 = proc.time()
    Sys.sleep(runif(1, min = 0, max = 0.8))
    p2 = proc.time() - p1
    Sys.sleep(1 - p2[3]) #basically sleep for whatever is left of the second
  })
   user  system elapsed 
   0.00    0.00   10.02

Upvotes: 15

Thierry
Thierry

Reputation: 18487

The shiny package has a function invalidateLater() which can be use to trigger functions. Have a look at http://shiny.rstudio.com/gallery/timer.html

Upvotes: 2

Related Questions