【问题标题】:Java socket: two newlines faster than one newlineJava套接字:两个换行符比一个换行符快
【发布时间】:2018-11-20 10:03:30
【问题描述】:

我有一个简单的客户端-服务器应用程序。服务器使用 Java,客户端使用 Python3。服务器等待单个客户端,然后以下列方式与其永久通信。服务器从客户端读取一行,并将消息“yyyy”发回。因此,从客户端来看,对话可能如下所示:

xxxx
> yyyy
xxxx
> yyyy
xxxx
> yyyy
...

我遇到的问题是通信速度。我测量了服务器读取客户端请求的时间,大约是40ms。但最令人惊讶的是,如果客户端在其每条消息中附加一个额外的换行符 '\n',则持续时间会下降到 ~0 毫秒。这可能是什么原因,我该如何解决,这样我就不必在每个客户的请求中都包含人工换行符?

为了完整起见,我还提供了服务器端和客户端代码。

服务器端:

import java.io.*;
import java.net.*;
import java.time.*;
import java.util.*;

class Server {
  public static void main (String[] args) {
    Clock clock = Clock.systemDefaultZone();
    try {
      ServerSocket server = new ServerSocket();
      server.bind(new InetSocketAddress("127.0.0.1", 4248));
      Socket client = server.accept();

      Scanner sc = new Scanner(client.getInputStream());
      PrintStream ps = new PrintStream(client.getOutputStream());

      while (true) {
        Instant start = clock.instant();
        String msg = sc.nextLine();
        Instant end = clock.instant();
        System.err.format("Took me %d ms to receive the message\n", Duration.between(start, end).getNano() / 1000000);
        ps.println("yyyy");
      }
    }
    catch (IOException exc) {}
  }
}

客户端:

import socket, sys

sock = socket.create_connection(("127.0.0.1", 4248))
fin = sock.makefile('r')
fout = sock.makefile('w')

while True:
  print("xxxx", file = fout, flush = True)
  msg = fin.readline().rstrip('\n');
  print(msg, file = sys.stderr)

我们通过将“xxxx”替换为“xxxx\n”来获得“快速”客户端。注意Python3会自动在每条消息后打印一个换行符,所以前者真的是“xxxx\n”,后者是“xxxx\n\n”。

【问题讨论】:

  • 你确定你总是得到 0ms 的变化吗?我预计 40ms 和 0ms 之间的交替:40ms、0ms、40ms、0ms、40ms、0ms ...
  • 是的,这就是它如此令人惊讶的原因。好像插座有快速交替输入和输出的问题,但如果比率为 1:2,则问题不大......
  • 很有趣,我在这里测试了它,但是在 Windows 机器上使用了 python 2(这就是我安装的)和 java 8。我在 xxxx 和 xxxx 之间没有区别\n - 总是 0-1ms
  • 我可以在旧的 linux 笔记本电脑上使用 Java 8 和 Python 3 复制 OP 的发现。
  • 当我在客户端中将print("xxxx", ...) 放在while True 之前时,测量的时间按以下模式重复:40, 0, 0, 40, 0 0, ... 有两个prints在循环之前,模式变为 40, 0, 0, 0, 40, 0, 0, 0, ...

标签: java networking


【解决方案1】:

我测量服务器读取客户端请求所花费的时间

不仅如此,您还可以测量(至少部分地)客户端发送请求之前的时间。

只是猜测

Python 客户端是瓶颈,跟不上 Java 服务器。服务器的nextLine() 总是等待客户端打印一些东西。
当您将print("xxxx") 更改为print("xxxx\n") 时,会同时打印两行,这使客户端的行输出速率加倍。现在情况正好相反:客户端发送消息的速度比服务器处理它们的速度要快,并且客户端的 readline() 必须等待服务器。
请注意,在后一种情况下,消息在"xxxx""" 之间交替出现。这可能不是你想要的。但是,您可以使用print("xxxx\nxxxx")

您可以通过编写一个使用println("xxxx") 的Java 客户端来测试这个理论。假设 Java 客户端比 python 客户端快,我预计测量时间会小于 40 毫秒,但可能会超过 0 毫秒。

【讨论】:

  • 我刚刚测试了这个(客户端和服务器都使用 Java 8)。使用单个换行符,它正好慢两倍(80 毫秒)。有了两个换行符,它仍然是 0ms 超快。问题是,即使客户端比服务器慢,也无法解释为什么处理“xxxx”然后“”比只处理“xxxx”快。
  • 那我一定猜错了。消除可能的误解:why processing "xxxx" and then "" is faster than processing "xxxx"。我没有谈论在服务器上处理某些东西所花费的时间,而是服务器花费在等待输入上的时间,即客户端发送某些东西所花费的时间。使用print("xxxx\n"),每次循环迭代发送两行;使用print("xxxx") 时,只发送了一条线路——但两个呼叫应该花费大约相同的时间。同样使用xxxx\n,服务器的下一个输入"" 在服务器甚至发送回复之前就已经存在。
猜你喜欢
  • 2021-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-30
  • 2011-05-02
  • 2016-07-02
  • 1970-01-01
  • 2010-10-23
相关资源
最近更新 更多