使用JAVA从套接字读取数据时减少CPU开销

使用JAVA从套接字读取数据时减少CPU开销,java,multithreading,sockets,Java,Multithreading,Sockets,我有两个线程增加了CPU开销。 1.以同步方式从套接字读取数据。 2.正在等待接受来自其他客户端的连接 问题1,我只是试图读取来自客户机的任何数据,而我不能使用readline,因为传入的数据有新行,我将其标记为知道消息的头端。所以我在线程中使用这种方式,但是它增加了CPU开销 public static String convertStreamToString(TCPServerConnectionListner socket) throws UnsupportedEncodingExcep

我有两个线程增加了CPU开销。 1.以同步方式从套接字读取数据。 2.正在等待接受来自其他客户端的连接

问题1,我只是试图读取来自客户机的任何数据,而我不能使用readline,因为传入的数据有新行,我将其标记为知道消息的头端。所以我在线程中使用这种方式,但是它增加了CPU开销

 public static String convertStreamToString(TCPServerConnectionListner socket) throws UnsupportedEncodingException, IOException, InterruptedException {

        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getSocket().getInputStream()));
        // At this point it is too early to read. So it most likely return false
        System.out.println("Buffer Reader ready? " + reader.ready());
        // StringBuilder to hold the response
        StringBuilder sb = new StringBuilder();
        // Indicator to show if we have started to receive data or not
        boolean dataStreamStarted = false;
        // How many times we went to sleep waiting for data
        int sleepCounter = 0;
        // How many times (max) we will sleep before bailing out
        int sleepMaxCounter = 5;
        // Sleep max counter after data started
        int sleepMaxDataCounter = 50;
        // How long to sleep for each cycle
        int sleepTime = 5;
        // Start time
        long startTime = System.currentTimeMillis();
        // This is a tight loop. Not sure what it will do to CPU
        while (true) {
            if (reader.ready()) {
                sb.append((char) reader.read());
                // Once started we do not expect server to stop in the middle and restart
                dataStreamStarted = true;
            } else {
                Thread.sleep(sleepTime);
                if (dataStreamStarted && (sleepCounter >= sleepMaxDataCounter)) {
                    System.out.println("Reached max sleep time of " + (sleepMaxDataCounter * sleepTime) + " ms after data started");
                    break;
                } else {
                    if (sleepCounter >= sleepMaxCounter) {
                        System.out.println("Reached max sleep time of " + (sleepMaxCounter * sleepTime) + " ms. Bailing out");
                        // Reached max timeout waiting for data. Bail..
                        break;
                    }
                }
                sleepCounter++;
            }

        }
        long endTime = System.currentTimeMillis();

        System.out.println(sb.toString());
        System.out.println("Time " + (endTime - startTime));

        return sb.toString();
    }
问题2,我不知道什么是最好的方法,我只是有一个线程,不断等待其他客户,并接受它。但这也需要大量的CPU开销

 // Listner to accept any client connection
    @Override
    public void run() {

        while (true) {
            try {
                mutex.acquire();
                if (!welcomeSocket.isClosed()) {
                    connectionSocket = welcomeSocket.accept();
                   // Thread.sleep(5);
                }


            } catch (IOException ex) {
                Logger.getLogger(TCPServerConnectionListner.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InterruptedException ex) {
                Logger.getLogger(TCPServerConnectionListner.class.getName()).log(Level.SEVERE, null, ex);
            }
            finally
            {
                mutex.release();
            }

        }
    }
}
剖析器图片也会有帮助,但我想知道为什么SwingWorker线程需要那么多时间?

问题1的更新代码:

    public static String convertStreamToString(TCPServerConnectionListner socket) throws UnsupportedEncodingException, IOException, InterruptedException {

            byte[] resultBuff = new byte[0];
            byte[] buff = new byte[65534];
            int k = -1;
            k = socket.getSocket().getInputStream().read(buff, 0, buff.length);
                byte[] tbuff = new byte[resultBuff.length + k]; // temp buffer size = bytes already read + bytes last read
                System.arraycopy(resultBuff, 0, tbuff, 0, resultBuff.length); // copy previous bytes
                System.arraycopy(buff, 0, tbuff, resultBuff.length, k);  // copy current lot
                resultBuff = tbuff; // call the temp buffer as your result buff

        return new String(resultBuff);
    }

}
        ![snapshot][2]

您似乎在等待,直到超时后没有更多数据

我建议你用


一个更好的解决方案是不需要这样做,因为它有一个协议,允许您知道何时到达数据的末尾。只有当服务器的实现很差并且无法修复时,您才会这样做。

您似乎在等待,直到超时后没有更多数据

我建议你用



一个更好的解决方案是不需要这样做,因为它有一个协议,允许您知道何时到达数据的末尾。只有在服务器的实现很差且无法修复的情况下,才能执行此操作。

只需去掉
ready()
调用和块即可。你在ready()时做的每件事都是假的,这简直是在浪费时间,包括睡眠。
read()。
sleep()
不会。您要么睡眠时间不够长,这会浪费CPU时间,要么睡眠时间过长,这会增加延迟。偶尔你可能会在正确的时间睡觉,但这是100%的运气,不是好的管理。如果需要读取超时,请使用读取超时。

只需摆脱
ready()
调用和块。你在ready()时做的每件事都是假的,这简直是在浪费时间,包括睡眠。
read()。
sleep()
不会。您要么睡眠时间不够长,这会浪费CPU时间,要么睡眠时间过长,这会增加延迟。偶尔你可能会在正确的时间睡觉,但这是100%的运气,不是好的管理。如果需要读取超时,请使用读取超时。

对于问题1。100%CPU可能是因为您正在从BufferedReader.read()读取单个字符。相反,您可以将数据块读取到数组中,并将其添加到stringbuilder中。

对于问题1。100%CPU可能是因为您正在从BufferedReader.read()读取单个字符。相反,您可以将数据块读取到数组中,然后将其添加到stringbuilder中。

我不理解问题2。互斥是用来做什么的?另外,因为accept()是一个阻塞调用,所以CPU的使用应该是最小的。好吧,那不是CPU周期的大部分时间,第一个问题呢?。read()也会阻塞,那么为什么它会占用CPU周期呢?好的,现在有一个阻塞读取,但需要60毫秒。首先,你的CPU总使用量下降了吗?我在问,在其他线程中是否还有其他可以避免的循环。@我将提供netbeans profiler的快照。但有一点点,只有3%的负。我不明白问题2。互斥是用来做什么的?另外,因为accept()是一个阻塞调用,所以CPU的使用应该是最小的。好吧,那不是CPU周期的大部分时间,第一个问题呢?。read()也会阻塞,那么为什么它会占用CPU周期呢?好的,现在有一个阻塞读取,但需要60毫秒。首先,你的CPU总使用量下降了吗?我在问,在其他线程中是否还有其他可以避免的循环。@我将提供netbeans profiler的快照。它只做了一点点,只有3%的负。所以我最好删除while(true),然后读取,然后设置socket.setSortimeout()?它会影响read()函数吗?探查器可以报告read()和阻塞,但这并不意味着它正在使用CPU。这正是它所做的。顺便说一句,如果可以避免的话,我不会使用StringBuilder,最好在获得数据时进行处理。您认为使用Java.NIO会有帮助吗?。我想使用read()读取我得到的数据,但它会阻塞线程。您可以使用非阻塞IO,但非常复杂,但我不清楚您得到了什么。i、 在这种情况下,为什么阻塞线程是一个问题?所以我最好删除while(true),然后读取,然后设置socket.SetSoTimeout()?它会影响read()函数吗?探查器可以报告read()和阻塞,但这并不意味着它正在使用CPU。这正是它所做的。顺便说一句,如果可以避免的话,我不会使用StringBuilder,最好在获得数据时进行处理。您认为使用Java.NIO会有帮助吗?。我想使用read()读取我得到的数据,但它会阻塞线程。您可以使用非阻塞IO,但非常复杂,但我不清楚您得到了什么。i、 e.为什么在这种情况下阻塞线程是一个问题?@EJP我已经更新了帖子中的代码。读取()大约需要60毫秒。艾哈迈德·萨利赫:事实上这太多了,是吗?这就是数据到达的时间。无论你对代码做多少修改都不能改变它。@EJP我已经在文章中更新了代码。读取()大约需要60毫秒。艾哈迈德·萨利赫:事实上这太多了,是吗?这就是数据到达的时间。再多的修改代码也不能改变它。