【问题标题】:Why is Idle Python Thread Consuming upto 90% of CPU?为什么 Idle Python 线程消耗高达 90% 的 CPU?
【发布时间】:2019-06-19 10:09:39
【问题描述】:

这是我的第一个线程程序。我在这里面临一个奇怪的问题。我正在构建一个简单的调度程序,如 Django 中的应用程序,其中函数名称(定期执行)将连同它们的下一个执行时间一起存储在 Django 模型中。
执行管理命令启动一个线程,该线程连续运行,检查是否有任何函数的执行到期,如果是,则启动一个新线程来执行该函数。这样,为每个函数创建了单独的线程(至少,这就是想法!)。

class Command(BaseCommand):

    def __init__(self):
        super(Command, self).__init__()
        self.lock = None

    def handle(self, *args, **kwargs):
        self.lock = threading.RLock()
        t1 = threading.Thread(target=self.cron_thread)
        t1.start()
        t1.join()

    def cron_thread(self):
        while True:
            # Fetch only Active records
            scheduled_actions = Scheduler.objects.filter(active=True)
            for scheduled_action in scheduled_actions:
                # check if execution is due
                if scheduled_action.next_execution_time == datetime.now():
                    # creating a new thread
                    function_thread = threading.Thread(target=eval(scheduled_action.function_name), args=[self.lock])
                    function_thread.start()
                    function_thread.join()
                    scheduled_action.next_execution_time = local_timezone.localize(datetime.now() + relativedelta(minutes=scheduled_action.interval))
                    scheduled_action.run_now = False
                    scheduled_action.save()

    def somefunction(self):
        self.lock.acquire()
        # function body
        self.lock.release()

我创建的开始执行整个程序的命令是:python3 manage.py runcrons-debit

执行此命令后,我可以在 htop 结果中看到两个进程正在运行并消耗近 80% 的 CPU,如下图所示: View Image 请注意这里还没有调度程序记录处于活动状态。

当调度程序记录被激活并且函数实际运行时,htop 中显示的进程增加到三个,CPU 使用率急剧下降到 0.0%。如下图所示: View Image

这里有两件事我无法理解,

  • 一旦函数执行结束并且没有函数正在执行,htop 结果将返回到消耗几乎 80-90% CPU 的两个进程。为什么这里的空闲线程会消耗这么多 CPU?
  • 另外,当没有执行任何功能时,为什么仍然显示两个进程?我可以理解其中一个是命令本身,但是是什么导致创建第二个进程?
  • 【问题讨论】:

    • 您的条件scheduled_action.next_execution_time == datetime.now() 永远是True 的可能性非常低(datetime.now() 是一个日期时间对象,它包括小时、分钟、秒甚至微秒)。
    • 因为while True: do stuff ?使用计算能力?使用 30 秒、1 分钟、10 分钟的睡眠时间,具体取决于您需要的分辨率。更好:使用调度程序并让每个需要它的线程在 x 时间重新启动自己.. 参见 f.e. stackoverflow.com/questions/2398661/…

    标签: python django python-3.x python-multithreading django-management-command


    【解决方案1】:

    cron_thread 有一个无限循环。此循环首先检索计划的操作,然后循环它们。对于每个操作,如果该操作被安排在当前的确切时间,则执行该操作。

    如果没有安排任何操作,则循环将一遍又一遍地继续检索计划的操作。如果有一个动作,它会检查现在是否是执行它的时间。这是另一个问题:datetime.datetime.now() 具有非常高的精度(最接近微秒),因此它与操作的预定时间相匹配的机会非常低。这意味着您的循环将检索所有计划的操作,循环所有操作,然后返回顶部。

    如果计划动作的时间与当前时间不匹配,则将执行该动作,然后内部循环移动到下一个动作。当它循环遍历所有动作时,它会回到顶部并再次检索所有动作。

    基本上,您的程序会不断将任何计划的操作与当前时间进行比较。这需要处理能力。执行这些操作的更好方法是检查每个新操作的时间,因为它被添加到任务列表中,计算必要的延迟,直到需要执行该操作,然后设置一个计时器以在必要后执行该操作延迟(time.sleep 在线程中,aftertkinter 中调用,诸如此类)。

    【讨论】:

    • 这是一个很好的建议!目前,我将 time.sleep() 的持续时间硬编码为 1 分钟,因为我的调度程序之一的间隔为 2 分钟,另一个为 3 分钟。使用 sleep() 后 CPU 使用率下降到几乎 0.0%。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-22
    • 2015-05-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多