Почему Idle Python Thread потребляет до 90% процессорного времени? - PullRequest
0 голосов
/ 25 января 2019

Это моя первая программа. Здесь я сталкиваюсь со странной проблемой. Я создаю простой планировщик, например, приложение в Django, где имена функций (которые будут выполняться периодически) будут храниться в Django Model вместе с их следующим временем выполнения.
Команда управления выполняется для запуска потока, который работает непрерывно, чтобы проверить, требуется ли выполнение какой-либо функции, если да, запускается новый поток для выполнения этой функции. Таким образом, создается отдельный поток для каждой функции (по крайней мере, это идея!).

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% ЦП, как показано на следующем рисунке: Просмотр изображения Обратите внимание, что записи планировщика еще не активны.

Когда записи планировщика становятся активными и когда функция фактически выполняется, процессы, отображаемые в htop , увеличиваются до трех, а загрузка ЦП резко снижается до 0,0%. Как показано на следующем изображении: Просмотр изображения

Здесь есть две вещи, которые я не могу понять,

как только выполнение функции закончено и функция не выполняется, результат htop возвращается к двум процессам, которые потребляют почти 80-90% ЦП. Почему пустые потоки здесь потребляют так много ресурсов ЦП? Кроме того, когда никакая функция не выполняется, почему все еще отображаются два процесса? Я понимаю, что одна из них относится к самой команде, но что вызывает создание второго процесса?

1 Ответ

0 голосов
/ 25 января 2019

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

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

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

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

...