Загрузка процессора 100%
От: xBlackCat Россия  
Дата: 10.10.05 13:50
Оценка:
Доброго времени суток.

Пишу многопоточное приложение и очень напрягает загрузка процессора под 100% во время его работы.
Суть приложения заключается в следующем: создать несколько подключений к серверу и посылать/принимать комманды от оного. Подключение открывается отдельным сокетом и его(подключение) обслуживают два потока — один для чтения/записи, второй для исполнения накопленных комманд от сервера. Код примерно следующий:

Поток для обслуживания сокета:
   public void run() {
    try {
      while (socketListenerThread == Thread.currentThread()) {
        if (selector.select() > 0)
          for (Iterator<SelectionKey> i = selector.selectedKeys().iterator();
               socketListenerThread == Thread.currentThread() && i.hasNext();) {
            SelectionKey key = i.next();
            i.remove();
            if (key.isValid()) {
              if (key.isConnectable()) {
                SocketChannel sc = (SocketChannel) key.channel();
                sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
                sc.finishConnect();
              } else if (key.isReadable()) {
                readPacket(); // Прочитать пакет и сохранить в очереди команд
                synchronized (commandProcessor) {
                  commandProcessor.notify();
                }
              } else if (key.isWritable()) {
                writePackets(); // Взять из очереди комманду и отослать на сервер
              }
            }
          }
          Thread.yield();
      }
    } catch (IOException e) {
    }
        ... // Всё почистить за собой
  }


Поток, обрабатывающий очередь команд:
  public void run() {
    try {
      while (commandProcessorThread == Thread.currentThread()) {
        synchronized (this) { // этот this == commandProcessor из верхнего куска кода.
          wait();
        }
        while (inputQueue.size() > 0) {
          Command c = inputQueue.remove(0);
          handleCommand(c);
          Thread.yield();
        }
      }
    } catch (InterruptedException e) {
    } finally {
      socketListenerThread = null;
        if (selector != null)
          selector.wakeup();
    }
  }


Профайлер говорит, что всё время забирают выделленные жирным строки кода. В связи с этим такие вопросы: Как это лечится, и, в принципе, правильно ли организована работа потоков?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Rojac &mdash; Rsdn Offline JAva Client
Анонсы и обсуждение здесь
Автор: xBlackCat
Дата: 08.02.10
Re: Загрузка процессора 100%
От: Sahivi  
Дата: 10.10.05 14:05
Оценка:
извеняюсь что не разобрался в Вашем коде но могу точно сказать что, когда я писал много поточное приложение такого же типа у меня тоже проц грузился так. Причина — цикл функции run очень быстро крутился без задржек, я долго мучился прежде чем нашел из за чего.
Re: Загрузка процессора 100%
От: Lucker Беларусь http://lucker.intervelopers.com/
Дата: 10.10.05 14:06
Оценка: 8 (2)
Здравствуйте, xBlackCat, Вы писали:

BC>Поток, обрабатывающий очередь команд:

      while (commandProcessorThread == Thread.currentThread()) {
        synchronized (this) { // этот this == commandProcessor из верхнего куска кода.
                    while (inputQueue.size() == 0) {
                        wait();
                    }
        while (inputQueue.size() > 0) {
          Command c = inputQueue.remove(0);
          handleCommand(c);
          Thread.yield();
        }
      }
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re: Загрузка процессора 100%
От: yaroslav_v http://yaroslav-v.chat.ru
Дата: 10.10.05 14:09
Оценка: :)
a esli ubrat' stroku: Thread.yield(); ?
Re: Загрузка процессора 100%
От: Donz Россия http://donz-ru.livejournal.com
Дата: 10.10.05 14:14
Оценка:
Здравствуйте, xBlackCat, Вы писали:

BC>Пишу многопоточное приложение и очень напрягает загрузка процессора под 100% во время его работы.

BC>Суть приложения заключается в следующем: создать несколько подключений к серверу и посылать/принимать комманды от оного. Подключение открывается отдельным сокетом и его(подключение) обслуживают два потока — один для чтения/записи, второй для исполнения накопленных комманд от сервера. Код примерно следующий:

BC>Поток, обрабатывающий очередь команд:

BC>
BC>  public void run() {
BC>    try {
BC>      while (commandProcessorThread == Thread.currentThread()) {
BC>        synchronized (this) { // этот this == commandProcessor из верхнего куска кода.
BC>          wait();
BC>        }
BC>        while (inputQueue.size() > 0) {
BC>          Command c = inputQueue.remove(0);
BC>          handleCommand(c);
BC>          Thread.yield();
BC>        }
BC>      }
BC>    } catch (InterruptedException e) {
BC>    } finally {
BC>      socketListenerThread = null;
BC>        if (selector != null)
BC>          selector.wakeup();
BC>    }
BC>  }
BC>


BC>Профайлер говорит, что всё время забирают выделленные жирным строки кода.

Во время Thread.yield() поток отдаёт управление другим потокам, если им есть, что делать, а сам ждёт. Пока он ждёт, ресурсы он не тратит, но время идёт.
Re[2]: Загрузка процессора 100%
От: xBlackCat Россия  
Дата: 10.10.05 14:14
Оценка:
Здравствуйте, Sahivi, Вы писали:

S>извеняюсь что не разобрался в Вашем коде но могу точно сказать что, когда я писал много поточное приложение такого же типа у меня тоже проц грузился так. Причина — цикл функции run очень быстро крутился без задржек, я долго мучился прежде чем нашел из за чего.


А можно поподробнее — какой из двух циклов Вы имеете ввиду? И как исправили?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Rojac &mdash; Rsdn Offline JAva Client
Анонсы и обсуждение здесь
Автор: xBlackCat
Дата: 08.02.10
Re[2]: Загрузка процессора 100%
От: xBlackCat Россия  
Дата: 10.10.05 14:14
Оценка:
Здравствуйте, Lucker, Вы писали:

L>Здравствуйте, xBlackCat, Вы писали:


BC>>Поток, обрабатывающий очередь команд:

L>
L>      while (commandProcessorThread == Thread.currentThread()) {
L>        synchronized (this) { // этот this == commandProcessor из верхнего куска кода.
L>                    while (inputQueue.size() == 0) {
L>                        wait();
L>                    }
L>        while (inputQueue.size() > 0) {
L>          Command c = inputQueue.remove(0);
L>          handleCommand(c);
L>          Thread.yield();
L>        }
L>      }
L>


Чем это поможет?

И теперь нельзя будет выйти из потока не прервав его — выделенный цикл будет постоянно работать в конце работы при очереди нулевой длины.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Rojac &mdash; Rsdn Offline JAva Client
Анонсы и обсуждение здесь
Автор: xBlackCat
Дата: 08.02.10
Re[2]: Загрузка процессора 100%
От: xBlackCat Россия  
Дата: 10.10.05 14:16
Оценка:
Здравствуйте, yaroslav_v, Вы писали:

_>a esli ubrat' stroku: Thread.yield(); ?


Будет тоже загрузка 100% но всё будет намного запущенней.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Rojac &mdash; Rsdn Offline JAva Client
Анонсы и обсуждение здесь
Автор: xBlackCat
Дата: 08.02.10
Re[2]: Загрузка процессора 100%
От: Blazkowicz Россия  
Дата: 10.10.05 14:17
Оценка:
Здравствуйте, yaroslav_v, Вы писали:

_>a esli ubrat' stroku: Thread.yield(); ?


Тогда бесконечный цикл просто сожрет все ресурсы.
Re[3]: Загрузка процессора 100%
От: Lucker Беларусь http://lucker.intervelopers.com/
Дата: 10.10.05 14:18
Оценка:
Здравствуйте, xBlackCat, Вы писали:

BC>Здравствуйте, Lucker, Вы писали:


L>>Здравствуйте, xBlackCat, Вы писали:


BC>>>Поток, обрабатывающий очередь команд:

L>>
L>>                    while (inputQueue.size() == 0) {
L>>                        wait();
L>>                    }
L>>


BC>И теперь нельзя будет выйти из потока не прервав его — выделенный цикл будет постоянно работать в конце работы при очереди нулевой длины.


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

PS. RTFM
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[3]: Загрузка процессора 100%
От: Lucker Беларусь http://lucker.intervelopers.com/
Дата: 10.10.05 14:21
Оценка:
Здравствуйте, xBlackCat, Вы писали:

BC>Чем это поможет?


BC>И теперь нельзя будет выйти из потока не прервав его — выделенный цикл будет постоянно работать в конце работы при очереди нулевой длины.


кстати, если твой поток объяевлен как демон — jvm сама убъет его при завершении работы системы (если не останется ни одного не демон потока)
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[3]: Загрузка процессора 100%
От: Blazkowicz Россия  
Дата: 10.10.05 14:21
Оценка:
Здравствуйте, xBlackCat, Вы писали:

BC>Чем это поможет?


BC>И теперь нельзя будет выйти из потока не прервав его — выделенный цикл будет постоянно работать в конце работы при очереди нулевой длины.


Весь код за тебя писать никто не будет. Lucker тебе пытается сказать что надо пересмотреть свой код и выкинуть исполнение пустых циклов. Вот скажи зачем они? Зачем каждый раз "что-то" проверять. Если можно остановить действие потка до тех пор пока "это" не поризойдет?
Re[2]: Загрузка процессора 100%
От: Blazkowicz Россия  
Дата: 10.10.05 14:23
Оценка:
Здравствуйте, Donz, Вы писали:

D>Во время Thread.yield() поток отдаёт управление другим потокам, если им есть, что делать, а сам ждёт. Пока он ждёт, ресурсы он не тратит, но время идёт.


Угу, обычно в ОС занято совсем не много ресурсов, вот она и отдаёт все оставшиеся этим пустым циклам.
Re[4]: Загрузка процессора 100%
От: xBlackCat Россия  
Дата: 10.10.05 14:23
Оценка:
Здравствуйте, Lucker, Вы писали:

L>Здравствуйте, xBlackCat, Вы писали:


BC>>Здравствуйте, Lucker, Вы писали:


L>>>Здравствуйте, xBlackCat, Вы писали:


BC>>>>Поток, обрабатывающий очередь команд:

L>>>
L>>>                    while (commandProcessorThread == Thread.currentThread() && inputQueue.size() == 0) {
L>>>                        wait();
L>>>                    }
L>>>


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

Но разве это не то же самое, что и было? Размер очереди проверяется и так и этак. Только в моём коде проверка была вне куска synchronized.

Вопрос был ещё в другом. Чтобы не поломать логику, надо условие изменить (поправлено в коде).
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Rojac &mdash; Rsdn Offline JAva Client
Анонсы и обсуждение здесь
Автор: xBlackCat
Дата: 08.02.10
Re[5]: Загрузка процессора 100%
От: Lucker Беларусь http://lucker.intervelopers.com/
Дата: 10.10.05 14:26
Оценка:
Здравствуйте, xBlackCat, Вы писали:

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

BC>Но разве это не то же самое, что и было? Размер очереди проверяется и так и этак. Только в моём коде проверка была вне куска synchronized.

Ну так доступ к очереди не синхронизирован и поэтому поведение кода вообще трудно предсказать.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[4]: Загрузка процессора 100%
От: xBlackCat Россия  
Дата: 10.10.05 14:28
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, xBlackCat, Вы писали:


B>Весь код за тебя писать никто не будет. Lucker тебе пытается сказать что надо пересмотреть свой код и выкинуть исполнение пустых циклов. Вот скажи зачем они? Зачем каждый раз "что-то" проверять. Если можно остановить действие потка до тех пор пока "это" не поризойдет?


Вот я и хочу понять, чем этот код:
while (true) {
    synchronized(this) {
        wait();
    }
    while (size > 0) {
        size--;
    }
}


отличается от
while (true) {
    synchronized(this) {
        while(size == 0)
            wait();
    }
    while (size > 0) {
        size--;
    }
}

?
Можете подробнее объяснить?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Rojac &mdash; Rsdn Offline JAva Client
Анонсы и обсуждение здесь
Автор: xBlackCat
Дата: 08.02.10
Re[6]: Загрузка процессора 100%
От: xBlackCat Россия  
Дата: 10.10.05 14:29
Оценка:
Здравствуйте, Lucker, Вы писали:

L>Ну так доступ к очереди не синхронизирован и поэтому поведение кода вообще трудно предсказать.


Сама очередь синхронизирована:
    List inputQueue = Collections.synchronizedList(new ArrayList());
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Rojac &mdash; Rsdn Offline JAva Client
Анонсы и обсуждение здесь
Автор: xBlackCat
Дата: 08.02.10
Re[5]: Загрузка процессора 100%
От: Lucker Беларусь http://lucker.intervelopers.com/
Дата: 10.10.05 14:30
Оценка: 2 (1)
Здравствуйте, xBlackCat, Вы писали:

о хорошему надо было бы написать

while (commandProcessorThread == Thread.currentThread()) {
    Command c = null;
    synchronized (this) { // этот this == commandProcessor из верхнего куска кода.
        while (commandProcessorThread == Thread.currentThread() && inputQueue.size() == 0) {
            wait();
        }
        if (inputQueue.size() > 0) {
            c = inputQueue.remove(0);
        }
    }
    if (c != null) {
        handleCommand(c);
        Thread.yield();
    }
}
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re: Загрузка процессора 100%
От: dshe  
Дата: 10.10.05 14:32
Оценка: +1
Здравствуйте, xBlackCat, Вы писали:

BC>Доброго времени суток.


BC>Пишу многопоточное приложение и очень напрягает загрузка процессора под 100% во время его работы.

BC>Суть приложения заключается в следующем: создать несколько подключений к серверу и посылать/принимать комманды от оного. Подключение открывается отдельным сокетом и его(подключение) обслуживают два потока — один для чтения/записи, второй для исполнения накопленных комманд от сервера. Код примерно следующий:

Многопоточный код должен работать и без Thread.yield() если многопоточность вытесняющая (а она именно такая на большинстве современных платформ).

А вот такой код отдает душком:
synchronized (this) {
    wait();
}

synchronized (commandProcessor) {
    commandProcessor.notify();
}
--
Дмитро
Re[5]: Загрузка процессора 100%
От: Blazkowicz Россия  
Дата: 10.10.05 14:48
Оценка:
Здравствуйте, xBlackCat, Вы писали:

B>>Весь код за тебя писать никто не будет. Lucker тебе пытается сказать что надо пересмотреть свой код и выкинуть исполнение пустых циклов. Вот скажи зачем они? Зачем каждый раз "что-то" проверять. Если можно остановить действие потка до тех пор пока "это" не поризойдет?


BC>Вот я и хочу понять, чем этот код:

BC>Можете подробнее объяснить?

Самому интересно. И все же. Когда у тебя перестанут работать пустые циклы тогда и загрузка на 100% исчезнет. Скажешь что у тебя их нет?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.