Почему Idle Python Thread потребляет до 90% ресурсов процессора?

Это моя первая многопоточная программа. Я столкнулся со странной проблемой здесь. Я создаю простой планировщик, такой как приложение в 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

As soon as I execute this command, I can see in the htop results that two process are running and consuming almost 80% of CPU, as shown in the following image: View Image Please note here that no scheduler records are active yet.

When scheduler records are made active, and when the function actually runs, the processes displayed in htop increase to three and CPU usage decreases drastically to 0.0%. As shown in the following image: View Image

There are two things here that I can't understand,

  • как только выполнение функции завершено и функция не выполняется, результат htop возвращается к двум процессам, потребляющим почти 80-90% ЦП. Почему простаивающие потоки потребляют так много ресурсов процессора?
  • Also, when no function is being executed why are there still two process being displayed? I can understand one of them is of the command itself but what is causing the second process to be created?


  • person Abhishek Dalvi    schedule 25.01.2019    source источник
    comment
    Вероятность того, что ваше условие scheduled_action.next_execution_time == datetime.now() когда-либо будет True (datetime.now() — это объект даты и времени, включает в себя часы, минуты, секунды и даже микросекунды), очень мала.   -  person julienc    schedule 25.01.2019
    comment
    потому что while True: do stuff ? использует вычислительную мощность? используйте сон 30 с, 1 мин, 10 мин, в зависимости от разрешения, которое вам нужно. Лучше: используйте планировщик и пусть каждый поток, который в нем нуждается, перезапустится через x раз. stackoverflow.com/questions/2398661 /   -  person Patrick Artner    schedule 25.01.2019


    Ответы (1)


    cron_thread имеет бесконечный цикл. Этот цикл сначала извлекает запланированные действия, а затем зацикливается на них. Для каждого действия, если действие запланировано на точное текущее время, действие выполняется.

    Если никакие действия не запланированы, цикл будет просто продолжать извлекать запланированные действия снова и снова. Если есть действие, оно проверит, не пора ли его выполнить. Вот еще одна проблема: datetime.datetime.now() имеет очень высокую точность (ближайшую микросекунду), поэтому шансы, что оно совпадет с запланированным временем действия, очень малы. Это означает, что ваш цикл извлечет все запланированные действия, зациклится на всех действиях, а затем вернется к началу.

    На случай, если время запланированного действия совпадает с текущим временем, это действие будет выполнено, а затем внутренний цикл переходит к следующему действию. Когда он прокрутит все действия, он вернется к началу и снова получит все действия.

    По сути, ваша программа постоянно сравнивает любые запланированные действия с текущим временем. Это требует вычислительной мощности. Лучшим способом выполнения этих действий было бы проверять время для каждого нового действия, когда оно добавляется в список задач, вычислять необходимую задержку до того, как это действие нужно будет выполнить, а затем устанавливать таймер для выполнения этого действия после необходимого времени. задержка (time.sleep в потоке, after вызовы в tkinter и тому подобное).

    person TigerhawkT3    schedule 25.01.2019
    comment
    Это отличное предложение! На данный момент я жестко запрограммировал продолжительность времени для time.sleep() как 1 минуту, так как один из моих планировщиков имеет интервал 2 минуты, а другой - 3 минуты. % использования ЦП снизился почти до 0,0% после использования sleep(). Большое спасибо! - person Abhishek Dalvi; 28.01.2019