10

Using python I can easily increase the current process's niceness:

>>> import os
>>> import psutil

>>> # Use os to increase by 3
>>> os.nice(3)
3

>>> # Use psutil to set to 10
>>> psutil.Process(os.getpid()).nice(10)
>>> psutil.Process(os.getpid()).nice()
10

However, decreasing a process's niceness does not seem to be allowed:

>>> os.nice(-1)
OSError: [Errno 1] Operation not permitted

>>> psutil.Process(os.getpid()).nice(5)
psutil.AccessDenied: psutil.AccessDenied (pid=14955)

What is the correct way to do this? And is the ratchet mechanism a bug or a feature?

TDN169
  • 1,397
  • 2
  • 13
  • 31

4 Answers4

13

Linux, by default, doesn't allow unprivileged users to decrease the nice value (i.e. increase the priority) of their processes, so that one user doesn't create a high-priority process to starve out other users. Python is simply forwarding the error the OS gives you as an exception.

The root user can increase the priority of processes, but running as root has other consequences.

Colonel Thirty Two
  • 23,953
  • 8
  • 45
  • 85
6

This is not a restriction by Python or the os.nice interface. It is described in man 2 nice that only the superuser may decrease the niceness of a process:

nice() adds inc to the nice value for the calling process. (A higher nice value means a low priority.) Only the superuser may specify a negative increment, or priority increase. The range for nice values is described in getpriority(2).

Chris Seymour
  • 83,387
  • 30
  • 160
  • 202
0

I had the same Error [Errno 2] Operation not permitted.

I don't want to start my script with sudo so I came around with the following workaround:

def decrease_nice():
    pid = os.getpid()
    os.system("sudo renice -n -19 -p " + str(pid))

def normal_nice():
    pid = os.getpid()
    os.system("sudo renice -n 0 -p " + str(pid))
Javan R.
  • 2,011
  • 1
  • 19
  • 16
0

You can't decrease a nice value below 0 without sudo, but there is a way to "undo" the nice value applied earlier and get around the "ratchet mechanism"

The workaround is to use the threading module. In the example below, I start a function called run in it's own thread and it promptly sets its own nice value to 5. When it finishes, the main thread continues right along doing nothing very quickly at a nice value of 0. You can verify this by having the top command show threads with top -H

import os, threading

def run():
    os.nice(5)
    for x in range(500000000):
        x = x
    print("Done, going back to Nice 0")

thread = threading.Thread(target=run)
thread.start()
thread.join()

while True:
    x=1
SurpriseDog
  • 462
  • 8
  • 18