Skip to content

Instantly share code, notes, and snippets.

@Axlefublr
Created October 21, 2022 07:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Axlefublr/6920efd2bb8362650b6ac6f7da764012 to your computer and use it in GitHub Desktop.
Save Axlefublr/6920efd2bb8362650b6ac6f7da764012 to your computer and use it in GitHub Desktop.

Settimers are really useful

But to properly use them, we're going to learn the concept of threads

Here's a hotkey with a while loop

The idea is a toggle

You press the hotkey once, the tooltip starts following your mouse

Press it again: it disappears.

But it doesn't disappear, the hotkey doesn't work the second time

MaxThreadsPerHotkey fixes this, but it's much better to use a settimer instead

Now, the toggle is working as expected

Press once to enable, the second time to disable

Now, why does it suddenly work? Threads

Ahk is singlethreaded, meaning only one thing can be done at a time

While a line is executing, nothing else can be done in that moment

In other words, the thread is occupied

However!

While the interpreter is switching from one line to another, there's a time period when the thread is not occupied

Now it's not actually after every single line, more like every 16 milliseconds or so, depending on your CPU

This is because of how Windows works

It needs to disperse resources between all the numerous processes running at the same time

In those 16 milliseconds, windows checks for anything to do with a higher priority

It might not find anything, but the check will happen regardless

That's where settimers jump in

Once that check period is on, the settimer goes in between and executes whatever it needs to

So, instead of occupying the thread once it's completely free, it waits for the moment to interject into the thread that's currently running and does its thing

That's why a settimer that runs every millisecond is pretty much the same as 16 milliseconds

Because settimers wait for the nearest window they could jump into

So, they are limited in how often they can occupy the thread

Other precise methods to measure time are also limited in ahk, due to this same issue

When trying to test the time complexity of your function, you probably tried using TickCount

You didn't get precise results because the precision of TickCount is also about 16 milliseconds

So if you want to time your functions, you can either increase the input massively

Or use the dll call method that times a process

Don't ask me, I have no idea how to use it

Coming back to why the while loop method didn't work

The hotkey takes up the thread, and you can't use another hotkey while this one is in progress

Because once again, the thread is taken and only one thing can be done at a time

However, timers don't take up the thread as aggressively

Instead of taking it all for themselves, they say "Hey, I want to take the thread as soon as I can" Not as soon as literally now

That's what async is, at least in the context of ahk

And the only way to achieve this semi async, is using timers

Let's see how blocking the thread works in code

Here we have a function that returns zero the first 19 times it's called

Once you call it more than 19 times, it starts returning the number we've been incrementing

In the first scenario, we have a loop that keeps calling the function.

On the twentieth iteration,

It shows the first info and breaks

After that, we have the second info

And as you can see the order is how it's supposed to be

Here we have the same thing, but with a settimer instead

Even though we call the settimer first, when we run the script, the order is reversed.

This is because a timer does not occupy the thread

It basically says "run this function object at every next opportunity"

So, the "second" info runs before that first opportunity

This is big, as I'm sure you'll realize through trying out timers for yourself

Your understanding of threads is the most important knowledge for settimers

Right now we're going to get into the actual specifics

The first parameter of a settimer is a function object that you want to execute.

I go into detail on function objects in my video on them, as well as my video on arrow functions

Then you have your period in milliseconds.

Here, the function object will be called every second

If you specify a negative time, the timer will run only once, getting automatically deleted afterwards

If you have multiple timers, which one goes first will be decided by which is the closest in the timing

If it's the same, you can make one timer more important than the other using the third parameter: Priority

Although, you don't have to use it

When you want to delete a timer, meaning stop it, you specify 0 in its period

If the thread where you disable a timer was launched by a timer, you don't have to specify anything in the first parameter

However, if it's not, you have to specify the same function object in the first parameter

Even if your arrow functions are exactly the same, they won't work, because they actually resolve to different function objects in memory

If you want to use arrow functions, you'll have to extract it into a variable, and then use that variable

Same exact thing goes for the Bind method

But once again, not needed if the timer deletion is in a thread called by that same timer

That's about it on our tutorial on threads and settimers

I hope this video helped you clear up how both of those work

Have a good day :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment