Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to efficiently call a func after X hours?

Tags:

go

timer

I know I can do like this:

func randomFunc() {
    // do stuff
    go destroyObjectAfterXHours(4, "idofobject")
    // do other stuff
}

func destroyObjectAfterXHours(hours int, id string) {
    time.Sleep(hours * time.Hour)
    destroyObject(id)
}

but if we imagine destroyObjectAfterXHours is called a million times within a few minutes, this solution will be very bad.

I was hoping someone could share a more efficient solution to this problem.

I've been thinking about a potential solution where destruction time and object id was stored somewhere, and then there would be one func that would traverse through the list every X minutes, destroy the objects that had to be destroyed and remove their id and time info from wherever that info was stored. Would this be a good solution?

I worry it would also be bad solution since you will then have to traverse through a list with millions of items all the time, and then have to efficiently remove some of the items, etc.

like image 278
fisker Avatar asked Dec 30 '17 02:12

fisker


People also ask

How do you call a function after some time in react?

The setTimeout method allows us to run a function once after the interval of the time. Here we have defined a function to log something in the browser console after 2 seconds. const timerId = setTimeout(() => { console. log('Will be called after 2 seconds'); }, 2000);

How do I call API after some time?

Using setTimeout() We can pass an API call inside the setTimeout() to execute it after a certain delay. const res = await fetch(`https://jsonplaceholder.typicode.com/posts`); }, 2000); Once this timer is created, it will send the API request after two seconds.


2 Answers

The time.AfterFunc function is designed for this use case:

func randomFunc() {
    // do stuff
    time.AfterFunc(4*time.Hour, func() { destroyObject("idofobject") })
    // do other stuff
}

time.AfterFunc is efficient and simple to use.

As the documentation states, the function is called in a goroutine after the duration elapses. The goroutine is not created up front as in the question.

like image 60
Bayta Darell Avatar answered Oct 14 '22 02:10

Bayta Darell


So I'd agree with your solution #2 than number 1.

Traversing through a list of a million numbers is much easier than having a million separate Go Routines

Go Routines are expensive (compared to loops) and take memory and processing time. For eg. a million Go Routines take about 4GB of RAM.

Traversing through a list on the other hand takes very little space and is done in O(n) time.

A good example of this exact function is Go Cache which deletes its expired elements in a Go Routine it runs periodically

https://github.com/patrickmn/go-cache/blob/master/cache.go#L931

This is a more detailed example of how they did it:

type Item struct {
    Object     interface{}
    Expiration int64
}


func (item Item) Expired() bool {
    if item.Expiration == 0 {
        return false
    }
   return time.Now().UnixNano() > item.Expiration
}

func RemoveItem(s []Item, index int) []int {
     return append(s[:index], s[index+1:]...)
}

func deleteExpired(items []Item){ 
    var deletedItems  []int
    for k, v := range items {
        if v.Expired(){
            deletedItems = append(deletedItems, k)
        }
    }
    for key, deletedIndex := range deleteditems{ 
        items = RemoveItem(items, deletedIndex)
    }
}

The above implementation could definitely be improved with a linked list instead of an array but this is the general idea

like image 4
cjds Avatar answered Oct 14 '22 02:10

cjds