38

I've got a Python program that does time-consuming computations. Since it uses high CPU, and I want my system to remain responsive, I'd like the program to change its priority to below-normal.

I found this: Set Process Priority In Windows - ActiveState

But I'm looking for a cross-platform solution.

Craig McQueen
  • 41,871
  • 30
  • 130
  • 181

5 Answers5

48

Here's the solution I'm using to set my process to below-normal priority:

lowpriority.py

def lowpriority():
    """ Set the priority of the process to below-normal."""

    import sys
    try:
        sys.getwindowsversion()
    except AttributeError:
        isWindows = False
    else:
        isWindows = True

    if isWindows:
        # Based on:
        #   "Recipe 496767: Set Process Priority In Windows" on ActiveState
        #   http://code.activestate.com/recipes/496767/
        import win32api,win32process,win32con

        pid = win32api.GetCurrentProcessId()
        handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid)
        win32process.SetPriorityClass(handle, win32process.BELOW_NORMAL_PRIORITY_CLASS)
    else:
        import os

        os.nice(1)

Tested on Python 2.6 on Windows and Linux.

Craig McQueen
  • 41,871
  • 30
  • 130
  • 181
  • 1
    Nice solution, but why do you call sys.getwindowversion() instead of checking sys.platform? – Winston Ewert Sep 05 '11 at 13:59
  • 1
    I just want to know reliably whether I'm running on Windows or not. `sys.platform` [does have documented return values](http://docs.python.org/library/sys.html#sys.platform) but I wasn't sure if it was trustworthy--does it really return `'win32'` on 64-bit Windows? (believe it or not, I still haven't got a 64-bit Windows to try it on! I guess I should be able to at work now) – Craig McQueen Sep 05 '11 at 22:58
  • 3
    Tried on Win7 64bit (with Python 64bit): `sys.platform` indeed returns `'win32'` – Jonathan Livni Jan 18 '13 at 16:30
  • 2
    @CraigMcQueen; Confirming on 2008 R2 Server -- `sys.platform` returns "win32" – Molomby May 29 '14 at 06:11
  • why not just `win32process.SetPriorityClass(win32api.GetCurrentProcess(), win32process.HIGH_PRIORITY_CLASS)` – panda-34 Sep 09 '18 at 09:31
28

You can use psutil module.

On POSIX platforms:

>>> import psutil, os
>>> p = psutil.Process(os.getpid())
>>> p.nice()
0
>>> p.nice(10)  # set
>>> p.nice()
10

On Windows:

>>> p.nice(psutil.HIGH_PRIORITY_CLASS)
Giampaolo Rodolà
  • 12,488
  • 6
  • 68
  • 60
  • 5
    Thanks for the link. It's a pity that the API is different on the two platforms (`10` versus `psutil.HIGH_PRIORITY_CLASS`). "Cross platform" means "the same API on all platforms" I should think. – Craig McQueen Jun 06 '11 at 00:11
  • psutil.HIGH_PRIORITY_CLASS is just an integer constant which is needed because process priority on Windows works differently than on UNIX: http://msdn.microsoft.com/en-us/library/ms683211(v=vs.85).aspx That aside, we can consider psutil cross-platform in that it allows you to use: p.nice = some_number ...for setting process priority on both UNIX and Windows. The only difference is that on Windows some_number is saved in a pre-defined constants. That's all. – Giampaolo Rodolà Jun 06 '11 at 12:51
  • 1
    It's a shame Python community does this with portability. Their definition of "portable" is "we will implement whatever the OS lets us do easily". Why can't select() work on pipes in Windows? It's doable, but the OS doesn't do it for you, so it's not implemented. Python is portable as long as you never need any libraries, which is effectively never. – user1594322 Feb 14 '13 at 22:55
  • 7
    Certain things are just not portable *by nature*, independently from the language, and Python as a language makes no exception (basically because it can't). Now, I'd love to hear your opinion on how you would consistently re-design psutil's nice functionality in order to be compatible across POSIX and Windows platforms. If your proposal will be reasonable I will change the current API and thank you for your contribution, otherwise I will conclude you were just trolling, because I can't see any constructive suggestion in your message. – Giampaolo Rodolà Mar 11 '13 at 18:32
  • 1
    Process priorities are not "not portable by nature"; it's merely that no one has bothered to abstract a proper subset of the Linux, MacOS and Windows priority systems. Having the subprocess system in Python provide better control over process priorities wouldn't be that hard -- you simply implement a common subset of priority controls that are present in all OSes. All OSes understand the concepts of "high", "normal", "low," and "idle" priorities. You could simply map these general concepts onto niceness ranges in the Linux and BSD derivatives. – johnwbyrd Sep 19 '15 at 20:52
  • 4
    Careful, the Windows example does the opposite of the POSIX example. A nice value of 10 means low priority. – sebeck Mar 27 '17 at 07:27
  • This is a nice solution; for simplicity you can remove `import os` and the argument `os.getpid()` to Process as the current is the default. – Bastian Ebeling Sep 17 '19 at 12:25
  • Hi, I tried your method to set the pid with high priority in the script, import os, psutil p = psutil.Process(os.getpid()) p.nice(-20) ; but I get the following error i.e. psutil.AccessDenied: psutil.AccessDenied (pid=3618) I think I need to run the script as sudo but how I should I to that? – Murtaza Apr 01 '20 at 18:24
11

On every Unix-like platform (including Linux and MacOsX), see os.nice here:

os.nice(increment)
Add increment to the process’s “niceness”. Return the new niceness. Availability: Unix.

Since you already have a recipe for Windows, that covers most platforms -- call os.nice with a positive argument everywhere but Windows, use that recipe there. There is no "nicely packaged" cross-platform solution AFAIK (would be hard to package this combo up, but, how much extra value would you see in just packaging it?-)

djvg
  • 11,722
  • 5
  • 72
  • 103
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
4

If you don't have access to some of these modules you can potentially do it in Windows with:

import os  
def lowpriority():  
    """ Set the priority of the process to below-normal."""  
    os.system("wmic process where processid=\""+str(os.getpid())+"\" CALL   setpriority \"below normal\"")  

You can obviously distinguish OS types as with examples above for compatibility.

Captain Jack Sparrow
  • 971
  • 1
  • 11
  • 28
c1c2c3c4c
  • 41
  • 1
1

Here a code that work good for me:

import sys
import os
import psutil

os_used = sys.platform
process = psutil.Process(os.getpid())  # Set highest priority for the python script for the CPU
if os_used == "win32":  # Windows (either 32-bit or 64-bit)
    process.nice(psutil.REALTIME_PRIORITY_CLASS)
elif os_used == "linux":  # linux
    process.nice(psutil.IOPRIO_HIGH)
else:  # MAC OS X or other
    process.nice(20)  

For futher informations on the number and constant used in the code the full documentation is here:
https://psutil.readthedocs.io/en/latest/#

bfontaine
  • 18,169
  • 13
  • 73
  • 107
X0-user-0X
  • 814
  • 1
  • 5
  • 20