防止python进入睡眠模式(python上的Wakelock)

时间:2019-08-25 14:44:58

标签: python python-3.x linux windows sleep-mode

如何在不使用其他操作系统(Ubuntu,Windows ...)的情况下不使用额外的应用程序的情况下阻止python的睡眠模式,但是在大多数情况下,我需要Linux解决方案

我正在制作需要大量时间使用的应用。它占用了大约80%的CPU,因此用户只需启动此应用程序,然后再离开键盘即可。所以我想我需要锁定睡眠模式的系统api或库之类的东西。我敢肯定,它存在。例如,如果您在操作系统上打开任何视频播放器,则您的(PC,笔记本电脑)将不会进入睡眠模式,这与浏览器中的情况相同。

此外,Android(WakeLock)或Windows (SetThreadExecutionState)中也有同样的事情

5 个答案:

答案 0 :(得分:1)

Keep.Awake中的逻辑将在ubuntu或任何运行Gnome(包括Unity的新旧版本)的Linux Distro上解决您的问题,并且可以在Wayland和X上运行。

我在此处发布了类似问题的解决方案:https://askubuntu.com/a/1231975/183131

从逻辑上讲,请执行以下操作:

  1. 通过子进程使用DBus命令。Popen(...)清除睡眠/暂停计数器。
  2. 使用psutil.cpu_percent()查询cpu使用量 定期执行或在程序完成操作后重新放置睡眠配置。

您可以在此处查看代码,以获取有关如何修改代码的详细信息或提示:https://launchpad.net/keep.awake

或者,您可以只在正在运行CPU密集型程序的Linux机器上运行keepawake.py,它将解决您的问题!就是这样!

示例用法来自网页:

要作为后台服务运行并将最低CPU负载设置为13%:

nohup ./keepawake.py -c 13 -r > /dev/null 2>&1 &

要作为后台服务运行,并在确定用户空闲之前将15分钟(900秒)设置为用户活动空闲时间:

nohup ./keepawake.py -u 900 -r > /dev/null 2>&1 &

要作为后台服务运行并将最小网络流量设置为5KB(5120字节):

nohup ./keepawake.py -s 5120 -r > /dev/null 2>&1 &

要作为后台服务运行并将时间表设置为1小时后进入睡眠/暂停状态(仅当确定用户活动,CPU和网络流量均处于空闲状态时才设置此值):

nohup ./keepawake.py -w 3600 -r > /dev/null 2>&1 &

要一次性运行以上所有设置(网络,CPU,用户空闲,睡眠计划),并将日志文件路径设置为“ /home/$USER/sleep/log/Keep.Awake/”,并提供详细输出:

nohup ./keepawake.py -s 5120 -c 13 -u 900 -w 3600 -l /home/$USER/sleep/log/Keep.Awake/ -v Detail -r > /dev/null 2>&1 &

答案 1 :(得分:1)

基于在互联网上找到的多种方法,我在下面提出了此模块。特别感谢@mishsx提供的Windows解决方法。

使用非常简单。您可以使用standby_lock或通过StandbyLock作为上下文管理器来选择装饰器方法:

## decorator
@standby_lock
def foo(*args, **kwargs):
    # do something lazy here...
    pass

## context manager
with StandbyLock():
    # ...or do something lazy here instead
    pass

foo执行期间,您的系统将保持清醒状态。

注意:仍有一些警告,因为Linux可能需要sudo特权,而OS XDarwin)尚未经过测试。

from functools import wraps
import platform

class MetaStandbyLock(type):
    """
    """

    SYSTEM = platform.system()

    def __new__(cls, name: str, bases: tuple, attrs: dict) -> type:
        if not ('inhibit' in attrs and 'release' in attrs):
            raise TypeError("Missing implementations for classmethods 'inhibit(cls)' and 'release(cls)'.")
        else:
            if name == 'StandbyLock':
                cls._superclass = super().__new__(cls, name, bases, attrs)
                return cls._superclass
            if cls.SYSTEM.upper() in name.upper():
                if not hasattr(cls, '_superclass'):
                    raise ValueError("Class 'StandbyLock' must be implemented.")
                cls._superclass._subclass = super().__new__(cls, name, bases, attrs)
                return cls._superclass._subclass
            else:
                return super().__new__(cls, name, bases, attrs)

class StandbyLock(metaclass=MetaStandbyLock):
    """
    """

    _subclass = None

    @classmethod
    def inhibit(cls):
        if cls._subclass is None:
            raise OSError(f"There is no 'StandbyLock' implementation for OS '{platform.system()}'.")
        else:
            return cls._subclass.inhibit()

    @classmethod
    def release(cls):
        if cls._subclass is None:
            raise OSError(f"There is no 'StandbyLock' implementation for OS '{platform.system()}'.")
        else:
            return cls._subclass.release()

    def __enter__(self, *args, **kwargs):
        self.inhibit()
        return self

    def __exit__(self, *args, **kwargs):
        self.release()

class WindowsStandbyLock(StandbyLock):
    """
    """

    ES_CONTINUOUS      = 0x80000000
    ES_SYSTEM_REQUIRED = 0x00000001

    INHIBIT = ES_CONTINUOUS | ES_SYSTEM_REQUIRED
    RELEASE = ES_CONTINUOUS

    @classmethod
    def inhibit(cls):
        import ctypes
        ctypes.windll.kernel32.SetThreadExecutionState(cls.INHIBIT)

    @classmethod
    def release(cls):
        import ctypes
        ctypes.windll.kernel32.SetThreadExecutionState(cls.RELEASE)

class LinuxStandbyLock(metaclass=MetaStandbyLock):
    """
    """

    COMMAND = 'systemctl'
    ARGS = ['sleep.target', 'suspend.target', 'hibernate.target', 'hybrid-sleep.target']

    @classmethod
    def inhibit(cls):
        import subprocess
        subprocess.run([cls.COMMAND, 'mask', *cls.ARGS])

    @classmethod
    def release(cls):
        import subprocess
        subprocess.run([cls.COMMAND, 'unmask', *cls.ARGS])

class DarwinStandbyLock(metaclass=MetaStandbyLock):
    """
    """

    COMMAND = 'caffeinate'
    BREAK = b'\003'

    _process = None

    @classmethod
    def inhibit(cls):
        from subprocess import Popen, PIPE
        cls._process = Popen([cls.COMMAND], stdin=PIPE, stdout=PIPE)

    @classmethod
    def release(cls):
        cls._process.stdin.write(cls.BREAK)
        cls._process.stdin.flush()
        cls._process.stdin.close()
        cls._process.wait()

def standby_lock(callback):
    """ standby_lock(callable) -> callable
        This decorator guarantees that the system will not enter standby mode while 'callable' is running.
    """
    @wraps(callback)
    def new_callback(*args, **kwargs):
        with StandbyLock():
            return callback(*args, **kwargs)
    return new_callback

答案 2 :(得分:1)

创建了示例TK应用程序以使窗口保持清醒状态

import tkinter as tk
import ctypes
import sys

def display_on():
    print("Always On")
    ctypes.windll.kernel32.SetThreadExecutionState(0x80000002)

def display_reset():
    ctypes.windll.kernel32.SetThreadExecutionState(0x80000000)
    sys.exit(0)


root = tk.Tk()
root.geometry("200x60")
root.title("Display App")
frame = tk.Frame(root)
frame.pack()

button = tk.Button(frame,
                   text="Quit",
                   fg="red",
                   command=display_reset)
button.pack(side=tk.LEFT)
slogan = tk.Button(frame,
                   text="Always ON",
                   command=display_on)
slogan.pack(side=tk.LEFT)

root.mainloop()

答案 3 :(得分:0)

我遇到了类似的情况,即一个进程花了足够长的时间执行自己的程序,以至于Windows会休眠。为了克服这个问题,我编写了一个脚本。

以下简单的代码段可以防止此问题。使用该脚本时,它将要求Windows在脚本运行时不要进入睡眠状态。 (在某些情况下,例如电池电量用尽时,Windows会忽略您的请求。)

    class WindowsInhibitor:
        '''Prevent OS sleep/hibernate in windows; code from:
        https://github.com/h3llrais3r/Deluge-PreventSuspendPlus/blob/master/preventsuspendplus/core.py
        API documentation:
        https://msdn.microsoft.com/en-us/library/windows/desktop/aa373208(v=vs.85).aspx'''
        ES_CONTINUOUS = 0x80000000
        ES_SYSTEM_REQUIRED = 0x00000001

        def __init__(self):
            pass

        def inhibit(self):
            import ctypes
            print("Preventing Windows from going to sleep")
            ctypes.windll.kernel32.SetThreadExecutionState(
                WindowsInhibitor.ES_CONTINUOUS | \
                WindowsInhibitor.ES_SYSTEM_REQUIRED)

        def uninhibit(self):
            import ctypes
            print("Allowing Windows to go to sleep")
            ctypes.windll.kernel32.SetThreadExecutionState(
                WindowsInhibitor.ES_CONTINUOUS)

要运行脚本,只需:

    import os

    osSleep = None
    # in Windows, prevent the OS from sleeping while we run
    if os.name == 'nt':
        osSleep = WindowsInhibitor()
        osSleep.inhibit()

    # do slow stuff

    if osSleep:
        osSleep.uninhibit()

答案 4 :(得分:0)

在谷歌搜索以找到解决方案时,没有可用的包,因此我决定将其打包以将其放入 PyPI:wakepy。我获得了跨平台支持的 PR,目前wakepy 支持Windows、Linux 和macOS。

命令行界面

python -m wakepy [-s]

使用可选的 -s 标志也会使屏幕保持开启状态。

Python API

from wakepy import set_keepawake, unset_keepawake

set_keepawake(keep_screen_awake=False)
# do stuff that takes long time
unset_keepawake()