Как я могу помешать циклу Java while потреблять> 50% моего процессора?

StackOverflow https://stackoverflow.com/questions/580419

  •  06-09-2019
  •  | 
  •  

Вопрос

Хорошо, я протестировал это на пустой программе, и просто работа while(true){} дала мне> 50% загрузки моего процессора.У меня есть игра, над которой я работаю, в которой в качестве основного цикла используется цикл while, и ее процессор все время загружен на 100.

Как я могу заставить Java повторять что-то снова и снова, не потребляя >50% моего процессора только для повторения?

Это было полезно?

Решение

Добавьте сон, чтобы перевести поток в режим ожидания на некоторый интервал:

Thread.sleep

Без сна цикл while будет потреблять все доступные вычислительные ресурсы.(Например, теоретически 100 % в одноядерной системе или 50 % в двухъядерной и так далее.)

Например, следующее будет повторяться один раз через while цикл примерно каждые 50 миллисекунд:

while (true)
{
    try
    {
        Thread.sleep(50);
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

Это должно немного снизить загрузку процессора.

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


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

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

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

Ниже приведен пример приложения Swing, основанного на JFrame который обновляет JLabel который будет содержать возвращаемое значение из System.currentTimeMillis.Процесс обновления происходит в отдельном потоке, а кнопка «Стоп» останавливает поток обновления.

Несколько концепций, которые проиллюстрирует пример:

  • Приложение с графическим интерфейсом на основе Swing с отдельным потоком для обновления времени. Это предотвратит блокировку потока графического интерфейса.(Называемый EDT или потоком отправки событий в Swing.)
  • Имея while цикл с условием цикла, которого нет true, но заменен на boolean который определит, следует ли поддерживать цикл в рабочем состоянии.
  • Как Thread.sleep факторы в реальном приложении.

Извините, пожалуйста, за длинный пример:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class TimeUpdate
{
    public void makeGUI()
    {
        final JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final JLabel l = new JLabel();

        class UpdateThread implements Runnable
        {
            // Boolean used to keep the update loop alive.
            boolean running = true;

            public void run()
            {
                // Typically want to have a way to get out of
                // a loop. Setting running to false will 
                // stop the loop.
                while (running)
                {
                    try
                    {
                        l.setText("Time: " +
                                System.currentTimeMillis());

                        Thread.sleep(50);
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }

                // Once the run method exits, this thread
                // will terminate.
            }
        }

        // Start a new time update thread.
        final UpdateThread t = new UpdateThread();
        new Thread(t).start();

        final JButton b = new JButton("Stop");
        b.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                t.running = false;
            }
        });

        // Prepare the frame.
        f.getContentPane().setLayout(new BorderLayout());
        f.getContentPane().add(l, BorderLayout.CENTER);
        f.getContentPane().add(b, BorderLayout.SOUTH);
        f.setLocation(100, 100);
        f.pack();
        f.setVisible(true);
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new TimeUpdate().makeGUI();
            }
        });
    }
}

Некоторые ресурсы о потоках и использовании Swing:

Другие советы

Thread.Sleep, возможно, не весь ответ.Для большинства игр процессора слишком много для необходимого объема работы.Просто поспать определенное время не так уж и эффективно, поскольку вы, скорее всего, либо по-прежнему будете сжигать слишком много ресурсов, либо недостаточно.Обычно вы хотите каким-то образом рассчитать время своей работы.

Если задуматься, экран обновляется только с определенной скоростью, обычно менее 100 раз в секунду.Я не знаком с API Java для такого рода вещей, но вам нужно узнать скорость обновления монитора, а затем обновлять его только один раз между каждым обновлением.

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

Вы действительно заняты ожиданием, то есть постоянно перегружаете свой процессор, проверяя одно или несколько условий, пока они не станут истинными.

Thread.sleep() не является решение.С использованием wait() и notify() методы позволяют вам делать именно то, что вы пытаетесь, но гораздо эффективнее.По сути, этот механизм позволяет потоку спать на объекте до тех пор, пока объект не решит, что что-то произошло, и не захочет разбудить все спящие на нем потоки.

Примеры кода можно найти здесь и здесь.

Этот должно быть вашим решением, а не скрывать свое занятое ожидание с помощью таймера.

Обычно в игровом цикле вы делаете небольшую паузу...например: http://developers.sun.com/mobility/midp/articles/game/

Хотя да, вы могли бы сделать

Thread.sleep(50)

как следует из принятого ответа, вы также можете позвонить

Thread.sleep(0) 

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

Способ сна (0) также максимизирует время, отведенное ОС вашему приложению, поскольку поток немедленно вернется в очередь процессора (вместо ожидания 50 мс перед этим), поэтому, если нет другого потока, ожидающего, ваш поток продолжит работу исполняется.

Кажется, ваша тема занята ожиданием.То есть он попадает в цикл, в котором ничего не делает.В такой ситуации он будет безрезультатно расходовать много циклов процессора.

Как упоминалось другими, ответом является Thread.sleep.

Это связано со свингом, но идея остается той же:попробуйте использовать шаблон Observer вместо wile(true).

Как насчет планировщика на основе Quartz-Spring, который выполняет работу снова и снова через повторяющиеся интервалы времени?

Если есть прерывание, то, вероятно, по какой-то причине.Лучший способ справиться с этим -

try {
    while (true) {
        Thread.sleep(50);
    }
} catch (InterruptException e) {
    Thread.currentThread().interrupt();
}

Однако этот цикл ничего не делает, поэтому я предлагаю вам просто удалить его.Довольно редко вам приходится долго ждать выполнения условия (в этом случае класс Condition является лучшим выбором), обычно вы можете преобразовать одно и то же поведение, чтобы вообще не нуждаться в цикле.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top