Setting Linux process niceness in Python

Python’s multiprocessing module gives developers the ability to write “multi-threaded” applications in spite of the infamous Global Interpreter Lock. Although multiprocessing requires more overhead, it enables more efficient use of a CPU’s cores, especially for compute-bound applications.

One of the recent tasks I had to complete for work was a high-performance application involving Ethernet streaming, GPU computation, CPU computation, file I/O, and a GUI. I had initially implemented all of this on a single thread, but moved on to use multiple Python processes once it became clear that a single process wasn’t going to cut it. As such, I ended up using a “pipelined” architecture, where each process was assigned a one of many tasks. Messages were passed between processes using the multiprocessing.Queue abstraction. Re-architecting the code in such a manner resulted in a significant runtime performance boost, but not nearly as much as I had hoped for (despite utilizing all four of my computer’s cores at near 100%).

Enter niceness, a process-specific value that signals how many cycles an active process should get relative to other active processes on an overburdened CPU or I/O bus. Note that a process’s niceness is different from its priority1 – lower niceness values get higher priority and vice versa. By increasing the niceness of the least demanding Python process, I was able to increase the application’s overall performance without having to add more pipelines or upgrade the hardware:

import os

def set_niceness(value):
    niceness = os.nice(0)
    os.nice(value - niceness)

Thus, to decrease a process’s priority (increase niceness) to its maximum value, all I had to do was call set_niceness(5). One caveat – regular users cannot decrease a process’s niceness without updating the machine’s conf files, even after increasing it from its default value:

>>> os.nice(-19)
Traceback (most recent call last):
  File "", line 1, in 
OSError: [Errno 1] Operation not permitted

To get around this, I added the following line to /etc/security/limits.conf (YMMV, I’m using Ubuntu):

liuf            -       priority        -20

Replace liuf with your username and you’re good to go. Note that this has the side effect of setting the default process niceness to -20, so use with caution.

1Linux processes also have a “priority” value, but I won’t get into that in this post. I believe it’s possible for a user to directly set a process’s priority as well, but I wouldn’t recommend it unless you a familiar with Linux schedulers. I, for one, am not.