I have a very file system intensive function that's being called many times a second. Wish to slow things down a little, anyone knows a way to throttle that function call in elisp?

[EDIT - 04/12/20]:

More info:

My Refreshing function calls projectile-project-p and it's half of my CPU use. As of profiler-report:

- tabbar-buffer-update-groups             156923  55%
 - let                                    156923  55%
  - sort                                  156923  55%
   - mapcar                               156922  55%
    - #<lambda 0xcae81b99>                156894  55%
     - save-current-buffer                156893  55%
      - list                              156756  55%
       - if                               156600  55%
        - funcall                         156600  55%
         - tabbar-buffer-groups           156599  55%
          - list                          156592  55%
           - if                           156592  55%
            - cond                        155466  54%
             - projectile-project-p       138487  48%
              - projectile-project-root   138481  48%
               - cl-some                  138347  48%

While Idle my implementation of the function tabbar-buffer-update-group is called multiple times a second (like using (message 'here'):

> here [210 times]
... 1s
> here [247 times]
... 2s 
> here [293 times]
... 3s

It gets higher when interacting with the interface (cursor moving, tab change, etc).

If i turn off my modifications in Tabbar everything gets so fast...

So: no bug in tabbar or emacs, I did it by myself.


  1. projectile-project-p is too slow for a UI element to call this often. Or is it a bug in projectile?
  2. I totally should tinker with tabbar hooks and make it refresh only when file is saved of buffer changes. But code isn't that straightforward.
  3. I totataly should try to customize a more modern implementation, like Centaur Tabs, or I could stop being silly and just stop trying to reimplement perspectives into a tab bar implementation, dunno,
  4. Now thinking on throttling, it may not work as it does in javascript and I can have a flicker or lock in my UI, will I?
  5. The best aproach could be a cached return with a time to expire as now it looks a stalled version won't happen.
  • The same comments made for emacs.stackexchange.com/q/57604/105 seem to apply here. – Drew Apr 12 '20 at 5:19
  • Please specify the behavior you want, as throttling. Are you looking just to slow down your function or to analyze a problem with it? If the former, maybe you can just use sleep-for (or sit-for). It's not very clear just what you're looking for. – Drew Apr 12 '20 at 5:25
  • @Drew It's an UI thing, won't sleep-for et al block the UI thread? I really don't know how parallel is elisp. – Henry Mazza Apr 12 '20 at 16:53
  • Elisp is not at all parallel. Yes, sleep-for blocks user input. – Drew Apr 12 '20 at 16:57

"Throttling" is probably not the right way to think about it.

There are likely two attack vectors:

  • change the caller of the function so it doesn't call you so often
  • change the function to make faster

the second can be done sometimes as follows:

(defun my-make-throttler ()
  (let ((last-time (float-time))
        (last-args 'dummy)
        (last-res ()))
    (lambda (&rest args)
      (if (and (< 1 (- (float-time) last-time))
               (equal args last-args))
        (setq last-time (float-time))
        (setq last-args args)
        (setq last-res (apply args))))))
(advice-add 'THEFUNCTIONTOTHROTTLE (my-make-throttler))
  • void-variable last-time and if I comment that goes to void-variable last-args ... – Henry Mazza Apr 12 '20 at 17:53
  • 1
    This code relies on lexical-binding being non-nil. IOW, add -*- lexical-binding:t -*- somewhere on the first line of the file in which you put that code. – Stefan Apr 12 '20 at 19:05
  • BTW, I changed the let to lexical-let and it looks like it went on. Still need debug. – Henry Mazza Apr 12 '20 at 20:34
  • 1
    lexical-let should die its honorable death. Do yourself a favor and add the -*- lexical-binding:t -*- at the head of the file. – Stefan Apr 12 '20 at 21:23
  • where it says last-res shouldn't say last-val? – Henry Mazza Apr 13 '20 at 0:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.