从套接字流中读取的线程占用更多 CPU

维西瓦·丹妮

在客户端socket中,我写了一个线程来连续读取socket的inputStream。这里我使用了一个while循环来无限读取。但是它需要更多的 CPU;因此可以减少CPU。请添加您的建议。还可以为 inputStream 添加侦听器。

线程代码:

public void run() {
while (!shutdown) {
    try {
        if(socketClient != null) {
            String message = socketClient.getMessage();
            logger.info ("Message size:" + message.length ());
            if(!message.equals("EmptyString")) {
                process(message);
            }
        } 
    } catch (Exception exception) {
        logger.info("Unable to read the socket message" +exception);
    }
}

}

SocketClient.java

public class SocketClient{
private volatile boolean isConnected;
private int              port;
private int              retryCount;
private long             startTime;
private String           hostName;
private DataInputStream  input;
private DataOutputStream output;
private Socket           socket;

public SocketClient(int port, String hostname) throws IOException {
    this.port     = port;
    this.hostName = hostname;
    establishConnection();
}


public void shutdown() {
    try {
        shutdown = true;
        input.close();
        output.close();
        socket.close();
    } catch (Exception e) {
        logger.debug("Exception in shutdown:" + e.getMessage());
    }
}

        public String getMessage() {
    BufferedReader reader = null;

    try {
        StringBuilder builder = new StringBuilder();
        reader = new BufferedReader(new 
                        InputStreamReader(tcpSocket.getInputStream()));

        do {
            builder.append(reader.readLine());
        } while((reader.ready()));

        if (builder.length() == 0)
            return "EmptyString";

        return builder.toString();
    } catch (IOException e) {
            return "EmptyString";
    } finally {
        try {
            if(reader != null)
                reader.close();
        } catch(IOException e) {
            logger.error("unable to close reader");
        }
    }
}

    private void establishConnection() {
        retryCount = 1;
        startTime  = System.currentTimeMillis();

        while (!shutdown) {
            try {
                if(!isConnected) {
                    socket = new Socket(hostName,port);
                    socket.setKeepAlive(true);
                    input       = new DataInputStream(socket.getInputStream());
                    output      = new DataOutputStream(socket.getOutputStream());
                    isConnected = true;
                    shutdown    = true;
                } 
            } catch (Exception exception) {
                isConnected = false;
                sleepFewSeconds();
                reconnectSocket();
            }
        }
    }

    private void reconnectSocket() {
        long endTime = startTime + 120000L;

        if(!(System.currentTimeMillis() < endTime)) {
            shutdown = true;
        }   
    }

    private void sleepFewSeconds() {
        try {
            TimeUnit.MILLISECONDS.sleep(20);
        } catch (InterruptedException interruptedException) {
            shutdown = true;
        }
    }

}
用户207421

我要在这里批评整个班级。您的具体问题的答案将会出现。

public class SocketClient{
private volatile boolean isConnected;

你不需要这个。socket == null也一样。

private int              port;
private int              retryCount;
private long             startTime;
private String           hostName;
private DataInputStream  input;
private DataOutputStream output;
private Socket           socket;

public SocketClient(int port, String hostname) throws IOException {
    this.port     = port;
    this.hostName = hostname;
    establishConnection();
}


public void shutdown() {
    try {
        shutdown = true;
        input.close();
        output.close();
        socket.close();

您不需要所有这些关闭,而且无论如何您都以错误的顺序执行它们。output.close()就足够了,无论如何它肯定应该是第一个。

    } catch (Exception e) {
        logger.debug("Exception in shutdown:" + e.getMessage());
    }
}

public String getMessage() {
    BufferedReader reader = null;

BufferedReader应该是一个实例变量,而不是一个局部变量。它被缓冲了。如果将其设为局部变量,则会丢失数据。

    try {
        StringBuilder builder = new StringBuilder();
        reader = new BufferedReader(new 
                        InputStreamReader(tcpSocket.getInputStream()));

        do {
            builder.append(reader.readLine());
        } while((reader.ready()));

你不需要这一切。如果消息是一行,你只需要return reader.readLine(),你需要调用者检查它是否为空,如果是,关闭套接字,停止读取等。如果消息超过一行,这是一种误用of ready():它当然不是消息结束的指示符。这似乎从你的问题下评论说,你不应该甚至有方法:只需要直接连接插座输入流的XML解析器,让做阅读。

        if (builder.length() == 0)
            return "EmptyString";

不要这样做。返回""或为空。不要为你的应用程序编造新的魔法字符串来解码。

        return builder.toString();
    } catch (IOException e) {
            return "EmptyString";

同上。

    } finally {
        try {
            if(reader != null)
                reader.close();

你应该不会在这里结束的读者。关闭它将关闭套接字,因此您永远不会收到另一条消息。

        } catch(IOException e) {
            logger.error("unable to close reader");
        }
    }
}

private void establishConnection() {
        retryCount = 1;
        startTime  = System.currentTimeMillis();

        while (!shutdown) {
            try {
                if(!isConnected) {
                    socket = new Socket(hostName,port);
                    socket.setKeepAlive(true);
                    input       = new DataInputStream(socket.getInputStream());
                    output      = new DataOutputStream(socket.getOutputStream());
                    isConnected = true;
                    shutdown    = true;

你为什么要shutdowntrue这里?什么都没有关闭。这是一个全新的插座。

                } 
            } catch (Exception exception) {
                isConnected = false;
                sleepFewSeconds();
                reconnectSocket();
            }

练习不好。Socket.connect(),由 内部调用new Socket(...),已经重试,而且您应该区分连接失败异常,而不是对它们都采用相同的策略。例如,“连接超时”已经阻塞了大约一分钟:您不需要再次睡眠;并且“连接被拒绝”意味着没有任何东西在听,所以重试是完全没有意义的。

    private void reconnectSocket() {
        long endTime = startTime + 120000L;

        if(!(System.currentTimeMillis() < endTime)) {
            shutdown = true;
        }   
    }

    private void sleepFewSeconds() {
        try {
            TimeUnit.MILLISECONDS.sleep(20);

这不是“几秒钟”。它是 20毫秒,这对于网络编程中至少两个数量级的 magnite 来说是不够的,当然应该有任何睡眠。

        } catch (InterruptedException interruptedException) {
            shutdown = true;

shutdown似乎永远不会是假的。我怀疑您是否考虑过它的真正含义,我怀疑您是否真的需要它。

至于你的调用代码:

public void run() {
while (!shutdown) {
    try {
        if(socketClient != null) {

如果socketClient为空,则此循环将无意义地旋转。这个方法肯定应该构造套接字客户端吗?

            String message = socketClient.getMessage();
            logger.info ("Message size:" + message.length ());

在这里,您无法检查 null 并且无法正确响应,这将关闭套接字并退出循环。相反,您将在这里获得 NPE。

            if(!message.equals("EmptyString")) {
                process(message);

看上面。不要给自己发送特殊的短信。如果对等方需要在某一天发送该消息会发生什么?

            }
        } 
    } catch (Exception exception) {
        logger.info("Unable to read the socket message" +exception);

不可接受。这个捕获在循环内部,它基本上忽略了异常。结果是,同样,这个循环将在任何异常上无意义地旋转。您调用的方法应该声明为 throw IOException,这就是您应该在这里捕获的全部内容。目前你甚至会旋转NullPointerException

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Python中的线程占用过多的CPU

来自分类Dev

Java套接字占用太多的CPU和虚拟内存

来自分类Dev

从套接字流中读取时是否需要线程休眠?

来自分类Dev

正在运行的线程占用大量CPU

来自分类Dev

倒置的占用CPU

来自分类Dev

CPU的“套接字”参数是什么?

来自分类Dev

SLURM设置节点因套接字核心线程cpu计数低而耗尽

来自分类Dev

异步CPU读取和GPU + CPU计算

来自分类Dev

CPU之间的线程分配?

来自分类Dev

从Lisp中的套接字流读取行

来自分类Dev

如何确定应用程序中在PerfMon中占用100%CPU使用率的线程?

来自分类Dev

从线程中的Java TCP套接字读取

来自分类Dev

在多CPU系统中混合CPU

来自分类Dev

单线程程序占用的CPU是否太低?

来自分类Dev

Java多线程程序不占用大量CPU

来自分类Dev

使用Thread.Sleep防止线程占用CPU

来自分类Dev

Python:为什么等待线程占用这么多 CPU

来自分类Dev

占用大量CPU资源的解析

来自分类Dev

SQLite查询占用太多CPU

来自分类Dev

占用大量CPU的从属属性

来自分类Dev

RxJava sample()占用大量CPU

来自分类Dev

“ ps”占用了99%的CPU

来自分类Dev

“ ps”占用了99%的CPU

来自分类Dev

占用大量CPU资源的解析

来自分类Dev

NSDate处理非常占用CPU

来自分类Dev

SpriteKit占用大量CPU资源

来自分类Dev

“ps”占用了 99% 的 CPU

来自分类Dev

iOS CPU配置文件:为什么此线程会占用99.9%的CPU?

来自分类Dev

如何在Linux C中以编程方式查找cpu套接字和每个套接字的核心数