I made a little Slack bot to amuse my friends. This thing is not exactly pushing the bounds of computer science, but it was fun to write: it listens to conversations on a Slack channel, and has a bunch of phases it knows how to reply to. It runs on a Google Compute Engine VM.
I'd been using the same VM for a bunch of different personal projects and, a while after adding my bot, I started to get warnings about resource usage. I didn't want to investigate just then, so I took GCE's recommendation and let it upgrade me from the tiniest machine type, "micro", to a "small" one. And I thought no more about it until the bills came in. My cloud bills have always been in pennies. How am I suddenly spending $16 per month?
The cloud console showed something surprising: the bigger VM was still using 100% CPU. My bot was somehow asking the CPU to work all the time. Google was even suggesting I move up a machine size again. What are you doing with all of that CPU, little bot?
The code has a loop to continuously poll Slack for new messages to the channel and decide whether to reply. I wrote it like this:
while True: messages = get_new_messages() for message in messages: response = create_response(message) if response: post_response(response)
See the problem? This infinite loop works great except for one thing: as soon as it finishes running through the loop, it immediately starts again at the beginning. There's never a time when the program isn't asking the CPU to do something. It's a demanding little process!
The easiest way to fix it is to tell the code to pause between loops. This means that it might take a little longer for the bot to notice new messages on the channel (though I presume Slack was already rate limiting me a bit), so it needs to be a pause shorter than a human will notice. Let's try 0.2 seconds.
while True: messages = get_new_messages() for message in messages: response = create_response(message) if response: post_response(response) time.sleep(0.2)
So, for 200 milliseconds, the code stops asking the CPU to do anything. Since the loop takes 150 milliseconds to run when there are new messages to read -- and much less than 1 ms when there aren't -- the bot will now spend most of its time asleep.
Does it work? Well, here's the CPU graph immediately after I pushed the change :-D
That's a picture of me getting $15.99 back every month.
Processes are assigned to a specific CPU, btw, so if I'd had a second processor on the machine, utilization would have been a flat 50%. For fun (look, weird things become interesting when you're on vacation), I tested the old version of the code on a 2 CPU machine, and its CPU usage flatlined at exactly 50%. It was a satisfying "the world works as you understand it" moment.
Bot code is at https://github.com/whereistanya/screambot.