2014-12-25 2 views
0

Я использую ниже клиентскую нить для подключения к моему NIO-серверу.Запуск потока занимает много cpu

class RunnableDemo implements Runnable { 
    private Thread t; 
    private String threadName; 

    InetAddress host = null; 
    int port = 9090; 

    RunnableDemo(String name) { 
     threadName = name; 
     System.err.println("Creating " + threadName); 

    } 

    public void run() { 
     System.err.println("Running " + threadName); 
     try { 
      SocketChannel socketChannel = SocketChannel.open(); 

      socketChannel.configureBlocking(false); 

      socketChannel.connect(new InetSocketAddress(host, port)); 

      while (!socketChannel.finishConnect()) 
       ; 

      System.out.println("Thread " + threadName + " Connected"); 

      while (true) { 
       ByteBuffer buffer = ByteBuffer.allocate(1024); 
       if (socketChannel.read(buffer) != 0) { 
        buffer.flip(); 
        byte[] bytes = new byte[buffer.limit()]; 
        buffer.get(bytes); 
        System.out.println(threadName+ ":" + new String(bytes)); 
        buffer.clear(); 
       } 
      } 

     } catch (Exception e) { 
      System.out.println("Thread " + threadName + " interrupted."); 
      e.printStackTrace(); 
     } 
     System.out.println("Thread " + threadName + " exiting."); 
    } 

    public void start() { 
     System.out.println("Starting " + threadName); 
     try { 
      host = InetAddress.getByName("127.0.0.1"); 
      if (t == null) { 
       t = new Thread(this, threadName); 
       t.start(); 
      } 
     } catch (UnknownHostException e) { 
      e.printStackTrace(); 
     } 
    } 

} 

Это код на стороне сервера. когда я работаю на сторону сервера, только процессор не более 5%, но при запуске клиента для каждого использования нити центрального процессора поднимет около 20-30%

public class EchoServer { 
    private static final int BUFFER_SIZE = 1024; 

    private final static int DEFAULT_PORT = 9090; 

    private long numMessages = 0; 

    private long loopTime; 

    private InetAddress hostAddress = null; 

    private int port; 

    private Selector selector; 

    // The buffer into which we'll read data when it's available 
    private ByteBuffer readBuffer = ByteBuffer.allocate(BUFFER_SIZE); 

    int timestamp=0; 

    public EchoServer() throws IOException { 
     this(DEFAULT_PORT); 
    } 

    public EchoServer(int port) throws IOException { 
     this.port = port; 
     hostAddress = InetAddress.getByName("127.0.0.1"); 
     selector = initSelector(); 
     loop(); 
    } 

    private Selector initSelector() throws IOException { 
     Selector socketSelector = SelectorProvider.provider().openSelector(); 

     ServerSocketChannel serverChannel = ServerSocketChannel.open(); 
     serverChannel.configureBlocking(false); 

     InetSocketAddress isa = new InetSocketAddress(hostAddress, port); 
     serverChannel.socket().bind(isa); 
     serverChannel.register(socketSelector, SelectionKey.OP_ACCEPT); 
     return socketSelector; 
    } 

    private void loop() { 
     for (;true;) { 
      try { 
       selector.select(); 
       Iterator<SelectionKey> selectedKeys = selector.selectedKeys() 
         .iterator(); 
       while (selectedKeys.hasNext()) { 
        SelectionKey key = selectedKeys.next(); 
        selectedKeys.remove(); 
        if (!key.isValid()) { 
         continue; 
        } 
        // Check what event is available and deal with it 
        if (key.isAcceptable()) { 
         accept(key); 

        } else if (key.isWritable()) { 
         write(key); 
        } 
       } 
       Thread.sleep(3000); 
       timestamp+=3; 
      } catch (Exception e) { 
       e.printStackTrace(); 
       System.exit(1); 
      } 



     } 
    } 

    private void accept(SelectionKey key) throws IOException { 

     ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel(); 

     SocketChannel socketChannel = serverSocketChannel.accept(); 
     socketChannel.configureBlocking(false); 
     socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true); 
     socketChannel.setOption(StandardSocketOptions.TCP_NODELAY, true); 

     socketChannel.register(selector, SelectionKey.OP_WRITE); 

     System.out.println("Client is connected"); 
    } 

    private void write(SelectionKey key) throws IOException { 
     SocketChannel socketChannel = (SocketChannel) key.channel(); 
     ByteBuffer dummyResponse = ByteBuffer.wrap(("ok:" + String.valueOf(timestamp)) .getBytes("UTF-8")); 

     socketChannel.write(dummyResponse); 
     if (dummyResponse.remaining() > 0) { 
      System.err.print("Filled UP"); 
     } 
     System.out.println("Message Sent"); 
    // key.interestOps(SelectionKey.OP_READ); 
    } 
} 

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

Когда я отслеживаю сектор производительности моей панели задач (Windows), генерируя каждый экземпляр этого потока, использование ЦП на моем ПК (я использую 2.6-ядерный процессор i5) увеличиваю с 30% и генерируя 3 потока Использование процессора составляет около 100% !!!

Мне интересно, в чем проблема с приведенным выше кодом, который занимает 30% моего процессора.

+0

@ Hussein BehbudiRad Распределите буфер за пределами цикла, и каждый раз, когда вы хотите использовать его с помощью метода чтения, очистите его. –

+0

Когда ваш метод чтения достигнет конца потока, он вернет -1, поэтому внутри вашего цикла чтения вы должны проверить, есть ли 'socketChannel.read (buffer)> 0', чтобы избежать ненужных работ. –

+0

ваши права. Я изменил '! =' На '>', а также переместил выделение «ByteBuffer» перед оператором «while», но никаких изменений в производительности процессора –

ответ

2

Я вижу две возможные причины для высокой загрузки процессора.

  1. Вы используете нелипкая I/O некстати, в силу (в действительности) повторно опрос канала для завершения подключения и чтения данных. В этом конкретном случае использования вам лучше рекомендуется использовать блокирующий ввод-вывод. Пропускная способность данных будет (в значительной степени) одинаковой, и вы не будете тратить процессор на опрос.

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

  2. Запись на System.out также может использовать значительный ЦП ... внешний для JVM. Если стандартный вывод идет в обычное консольное приложение, которое отображает его на экране, тогда процесс рендеринга и рисования текста на экране ... и прокрутка ... может использовать достаточное количество CPU.

+0

На самом деле мне нужно отправить текстовый текст (всего 4 символа) всем моим подключенным клиентам. Клиенты выполняют свою работу, а также подключаются к серверу. после каждого 3-секундного сервера отправляет 4-значную строку и клиентский журнал на основе этой вещи. Лучше ли я использовать блокирующий сокет для этого предложения? –

+0

Я также разместил свой код сервера, если он может помочь. –

+0

Я прокомментировал system.out.println и вместо того, чтобы печатать, просто сохраните его на строковой переменной, но использование процессора не изменилось. –

-2

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

Я бы особенно спал, где выполняются внешние действия и ожидается латентность.

См. Также Thread.sleep.

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

+0

У меня есть сон (3000) на моей стороне сервера. он отправляет сообщения каждые 3 секунды. таким образом, необходимо, чтобы я также добавил thread.slepp на стороне клиента? –

+0

Ну, обычно, если ваш клиент не выкачивает запросы. Добавление сна должно помочь процессору, но при стоимости всего. Ваши sysouts будут сравнительно медленными, поэтому их следует ждать, но не ожидайте значительного. – wmorrison365

+1

Минус 1 за неуместное, предотвращаемое и вводящее в заблуждение использование Sleep(). –

Смежные вопросы