简体   繁体   English

运行线程占用大量CPU

[英]Running thread takes much cpu

I am using below client thread for connecting to my NIO server. 我正在使用下面的客户端线程连接到我的NIO服务器。

    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();
        }
    }

}

This is my server side code. 这是我的服务器端代码。 when I running the server side only the CPU is not more than 5% but when I run client for each thread cpu usage will raise about 20-30% 当我运行服务器端时,仅CPU不会超过5%,但是当我为每个线程运行客户端时,CPU使用率将提高约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);
    }
}

Every thing works right. 一切正常。 Client and server can see each other and communicate. 客户端和服务器可以互相看到并进行通信。 In order to testing how much connection my code can accept I create several instances of above thread and here is the problem. 为了测试我的代码可以接受多少连接,我创建了上述线程的多个实例,这就是问题所在。

When I tracking the performance sector of my task panel(windows) by generating each instance of this thread the CPU usage of my PC (I am using a 2.6 core i5 CPU) raise with 30% and by generating 3 thread my cpu usage is about 100% !!! 当我通过生成该线程的每个实例来跟踪任务面板(windows)的性能扇区时,我的PC(我使用的是2.6核心i5 CPU)的CPU使用率提高了30%,并且通过生成3个线程,我的cpu使用率约为100%!!!

I am wondering what is the problem with above code that takes 30% of my CPU. 我想知道上面占用我30%CPU的代码的问题是什么。

I can see two potential causes for high CPU load. 我可以看到导致CPU高负载的两个潜在原因。

  1. You are using non-blocking I/O inappropriately, by (in effect) repeatedly polling the channel to complete the connect, and to read data. 通过(实际上)反复轮询通道以完成连接并读取数据,您在不适当地使用非阻塞I / O。 In this particular use-case, you would be better advised to used blocking I/O. 在此特定用例中,最好建议您使用阻塞I / O。 The data throughput will be (pretty much) the same, and you won't waste CPU by polling. 数据吞吐量将(几乎)相同,并且您不会通过轮询浪费CPU。

    Generally speaking, non-blocking I/O is only a good idea when the thread has other things to do instead of blocking. 一般来说,当线程有其他事情要做而不是阻塞时,非阻塞I / O只是一个好主意。

  2. Writing to System.out could also use significant CPU ... external to the JVM. 写入System.out也可能会System.out JVM外部的大量CPU。 If standard output goes to a typical console application that displays it on the screen, then the process of rendering and painting the text onto the screen ... and scrolling ... could use a fair amount of CPU. 如果将标准输出发送到在屏幕上显示它的典型控制台应用程序,则在屏幕上呈现和绘制文本并将其滚动的过程可能会占用大量CPU。

Can't see anything particular that would cause undue stress but I would suggest that you include a short sleep in your loop to ensure you don't hog the cpu. 看不到任何会引起过大压力的特殊情况,但我建议您在循环中进行短暂睡眠,以确保您不会占用CPU。 This includes hogging the cup from your main thread (which could be a server expected to do the important job of listening on oncoming connections). 这包括从您的主线程(这可能是一台服务器,有望在侦听即将到来的连接方面发挥重要作用)中cup起杯子。

I would especially sleep where external activities are executed and latency is expected. 在执行外部活动并预期会有延迟的地方,我尤其会睡觉。

See also Thread.sleep . 另请参见Thread.sleep

Having done so, I would test throughout against your original while monitoring cpu, memory, load, etc. 这样做后,我将在监视cpu,内存,负载等的同时针对您的原始版本进行全面测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM