【问题标题】:Socket listener is KILLING my CPU, how to improve performace of my code?套接字侦听器正在杀死我的 CPU,如何提高我的代码性能?
【发布时间】:2013-02-27 20:57:57
【问题描述】:

我已经实现了一个套接字侦听器来读取从 GPS 发送的数据,但它占用了我 90% 的 CPU。我知道这是我的代码造成的,但我看不到在哪里。

这是我的主要课程:

public class PortToDB {

    ServerSocket serverSocket = null;

    public void listenSocket(){
        try{
            serverSocket = new ServerSocket(50000);
        } catch (IOException e) {
            System.out.println("Could not listen on port 50000. " + e);
            System.exit(-1);
        }

        while(true){
            GPSData gd;
            try{
                gd = new GPSData(serverSocket.accept());
                Thread t = new Thread(gd);
                t.start();
            } catch (IOException e) {
                System.out.println("Accept failed: 50000. " + e);
                System.exit(-1);
            }
        }
    }

    public static void main(String[] args) {    
        PortToDB portToDb = new PortToDB();
        portToDb.listenSocket();
    }
}

这是我的 Runnable 类:

class GPSData implements Runnable {

    private Socket client;
    DBHandler dbhandler = new DBHandler();

    GPSData(Socket client) { this.client = client; }

    public void run(){
        String line;
        BufferedReader in = null;

    try{
        in = new BufferedReader(new InputStreamReader(client.getInputStream()));
    } catch (IOException e) {
        System.out.println("in or out failed");
        System.exit(-1);
    }

    while(true){
      try{
          if((line = in.readLine()) != null){
              dbhandler.dbInsert(line);
          }
      } catch (IOException e) {
          System.out.println("Read failed");
          System.exit(-1);
      }
    }
  }
}

【问题讨论】:

  • Code Review 或许能帮上忙/找个更好的地方问。
  • 总共创建了多少线程,多久创建一次,同时有多少线程在运行?高 CPU 使用率会在使用一段时间后立即开始吗?

标签: java multithreading sockets listener port


【解决方案1】:

如果readLine() 返回null,您必须关闭套接字,退出读取循环,然后忘记那个客户端。你在 EOS 旋转。

【讨论】:

  • I'm sorry EOS 是什么意思?
【解决方案2】:

不要为每个传入的请求创建新线程,而是使用线程池:

private ExecutorService executor = Executors.newFixedThreadPool(15);

// ...

gd = new GPSData(serverSocket.accept());
executor.submit(gd);

这样,您将消除在接收请求时创建无限线程的开销,而是在打开套接字端口接收请求之前创建有限线程。


另外,正如@EJB 所说,只要您从readLine() 收到null 作为流结束 (EOS) 的指示符,就退出客户端 for 循环。

【讨论】:

  • 连接数超过15怎么办??
  • 您还可以在读取线程中添加一个小的 Thread.sleep。这应该会减少一些负载并允许其他一些线程有机会处理那里的数据
  • 不会'导致其他等待连接的开销??
  • 我现在就试试这个戒指。
  • 这一切都无关紧要。他不需要在读取线程中休眠。读取是阻塞操作。更改为线程池并不能解决 100% CPU 使用率的问题。
【解决方案3】:

感谢所有回答我问题的人。

我通过结合 Eng.Fouad 和 EJP 的建议解决了这个问题:

这是我在代码中更改的内容:

执行者:

    private ExecutorService executor = Executors.newFixedThreadPool(15);

    try{
        gd = new GPSData(serverSocket.accept());
        executor.submit(gd);
    }

循环控制:

    try{            
        while((line = in.readLine()) != null){         
        dbhandler.dbInsert(line);
        }
    }

现在进程停留在 0% :)。

感谢 EJP 和 Eng.Fouad。

【讨论】:

  • @Eng.Fouad 我想知道你们是否同意这一点。
  • @EJP 我想知道你们是否同意这一点。
  • @EJP 我明白你在说什么,但我必须更具体一些。在这种特殊情况下,我正在测试每次更新之间大约 50 秒的(一个)GPS 连接,我现在正在开发机器中进行开发。当它投入生产时,将有 45 个 GPS 大约每 1-2 分钟更新一次。我不确定如何计算我应该在线程池中实现的线程的确切数量,但 15 似乎是一个很好的余量,可以允许这个增长空间。到目前为止,我愿意提供更多信息,您对我很有帮助。
  • @EJP 我同意你的观点,客户端代码中的无限循环是导致 100% CPU 使用率的原因,但是当你说 OP 不需要线程池时,我不同意你的观点。为每个传入请求创建一个新线程的开销如何?!
  • @Eng.Fouad 最初的问题是 a GPS,这意味着 one 客户端,因此 one 线程已启动一次。他可以在 15 个线程的固定线程池中生存,这表明他没有大量的新连接流量。因此,线程创建开销不是问题。如果有任何证据表明他需要线程池,我当然会提倡使用线程池,但没有。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-04
  • 1970-01-01
  • 1970-01-01
  • 2018-09-29
  • 2017-09-03
  • 1970-01-01
相关资源
最近更新 更多