Java SocketChannel:为什么如果我快速写msg,每条消息的延迟都很低,但当我每30秒写一条消息时,延迟就很高?

Java SocketChannel:为什么如果我快速写msg,每条消息的延迟都很低,但当我每30秒写一条消息时,延迟就很高?,java,sockets,networking,jvm,real-time,Java,Sockets,Networking,Jvm,Real Time,这一问题的发展现在在这一新问题中得到了明确的描述: 下面是一个简单服务器和客户端的源代码,用于演示和隔离问题。基本上,我是在为乒乓(客户机-服务器-客户机)消息的延迟计时。我从每1毫秒发送一条消息开始。我等待发送200k条消息,以便热点有机会优化代码。然后我把暂停时间从1毫秒改为30秒。令我惊讶的是,我的写和读操作变得相当慢 我不认为这是一个JIT/热点问题。我能够精确地指出本地JNI调用的较慢方法,以进行写入(write0)和读取。看起来你停顿的时间越长,它变得越慢 我正在寻找关于如何调试、理

这一问题的发展现在在这一新问题中得到了明确的描述:

下面是一个简单服务器和客户端的源代码,用于演示和隔离问题。基本上,我是在为乒乓(客户机-服务器-客户机)消息的延迟计时。我从每1毫秒发送一条消息开始。我等待发送200k条消息,以便热点有机会优化代码。然后我把暂停时间从1毫秒改为30秒。令我惊讶的是,我的写和读操作变得相当慢

我不认为这是一个JIT/热点问题。我能够精确地指出本地JNI调用的较慢方法,以进行写入(
write0
)和读取。看起来你停顿的时间越长,它变得越慢

我正在寻找关于如何调试、理解、解释或修复此问题的指针

Server.java:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class Server {

    private final ServerSocketChannel serverSocketChannel;
    private final ByteBuffer readBuffer = ByteBuffer.allocateDirect(1024);
    private final int port;
    private final int msgSize;

    public Server(int port, int msgSize) throws IOException {
        this.serverSocketChannel = ServerSocketChannel.open();
        this.port = port;
        this.msgSize = msgSize;
    }

    public void start() throws IOException {
        serverSocketChannel.socket().bind(new InetSocketAddress(port));
        final SocketChannel socketChannel = serverSocketChannel.accept(); // blocking mode...
        System.out.println("Client accepted!");
        socketChannel.configureBlocking(false);
        socketChannel.socket().setTcpNoDelay(true);
        Thread t = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    while(true) {
                        int bytesRead = socketChannel.read(readBuffer);
                        if (bytesRead == -1) {
                            System.out.println("Client disconnected!");
                            return;
                        } else if (bytesRead > 0) {
                            if (readBuffer.position() == msgSize) {
                                // have a full message there...
                                readBuffer.flip();
                                int bytesSent = socketChannel.write(readBuffer);
                                if (bytesSent != msgSize) throw new RuntimeException("Could not send full message out: " + bytesSent);
                                readBuffer.clear();
                            }
                        }
                    }
                } catch(Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.start();
        serverSocketChannel.close();
    }

    public static void main(String[] args) throws Exception {

        Server s = new Server(9999, 8);
        s.start();
    }
}
Client.java:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class Client implements Runnable {

    private static final int WARMUP = 200000;

    private final SocketChannel socketChannel;
    private final String host;
    private final int port;
    private final ByteBuffer outBuffer;
    private final ByteBuffer inBuffer = ByteBuffer.allocateDirect(1024);
    private final int msgSize;
    private final StringBuilder sb = new StringBuilder(1024);

    private int interval;
    private int totalMessagesSent;
    private long timeSent;
    private int mod;


    public Client(String host, int port, int msgSize) throws IOException {
        this.socketChannel = SocketChannel.open();
        this.host = host;
        this.port = port;
        this.outBuffer = ByteBuffer.allocateDirect(msgSize);
        this.msgSize = msgSize;
        for(int i = 0; i < msgSize; i++) outBuffer.put((byte) i);
        outBuffer.flip();
        this.interval = 1;
        this.mod = 20000;
    }

    public static long busySleep(long t) {
        long x = 0;
        for(int i = 0; i < t * 20000; i++) {
            x += System.currentTimeMillis() / System.nanoTime();
        }
        return x;
    }

    public void start() throws Exception {
        this.socketChannel.configureBlocking(false);
        this.socketChannel.socket().setTcpNoDelay(true);
        this.socketChannel.connect(new InetSocketAddress(host, port));

        while(!socketChannel.finishConnect()) {
            System.out.println("Waiting to connect");
            Thread.sleep(1000);
        }
        System.out.println("Please wait as output will appear every minute or so. After " + WARMUP + " messages you will see the problem.");
        Thread t = new Thread(this);
        t.start();
    }

    private final void printResults(long latency, long timeToWrite, long timeToRead, long zeroReads, long partialReads, long realRead) {
        sb.setLength(0);
        sb.append(new java.util.Date().toString());
        sb.append(" Results: totalMessagesSent=").append(totalMessagesSent);
        sb.append(" currInterval=").append(interval);
        sb.append(" latency=").append(latency);
        sb.append(" timeToWrite=").append(timeToWrite);
        sb.append(" timeToRead=").append(timeToRead);
        sb.append(" realRead=").append(realRead);
        sb.append(" zeroReads=").append(zeroReads);
        sb.append(" partialReads=").append(partialReads);
        System.out.println(sb);
    }

    @Override
    public void run() {

        try {

            while(true) {

                busySleep(interval);

                outBuffer.position(0);

                timeSent = System.nanoTime();

                int bytesSent = socketChannel.write(outBuffer);
                long timeToWrite = System.nanoTime() - timeSent;
                if (bytesSent != msgSize) throw new IOException("Can't write message: " + bytesSent);

                inBuffer.clear();
                long zeroReads = 0;
                long partialReads = 0;
                long timeToRead = System.nanoTime();
                long realRead = 0;
                while(inBuffer.position() != msgSize) {
                    realRead = System.nanoTime();
                    int bytesRead = socketChannel.read(inBuffer);
                    if (bytesRead == 0) {
                        zeroReads++;
                    } else if (bytesRead == -1) {
                        System.out.println("Other side disconnected!");
                        return;
                    } else if (bytesRead != msgSize) {
                        partialReads++;
                        realRead = -1;
                    } else {
                        realRead = System.nanoTime() - realRead;
                    }
                }

                long now = System.nanoTime();

                timeToRead = now - timeToRead;

                long latency = now - timeSent;

                if (++totalMessagesSent % mod == 0 || totalMessagesSent == 1) {
                    printResults(latency, timeToWrite, timeToRead, zeroReads, partialReads, realRead);
                }

                if (totalMessagesSent == WARMUP) {
                    this.interval = 30000;
                    this.mod = 1;
                }
            }

        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws Exception {

        Client client = new Client("localhost", 9999, 8);
        client.start();
    }
}
import java.io.IOException;
导入java.net.InetSocketAddress;
导入java.nio.ByteBuffer;
导入java.nio.channels.SocketChannel;
公共类客户端实现可运行{
私人静态最终内部预热=200000;
私人最终SocketChannel SocketChannel;
私有最终字符串主机;
私人最终国际港口;
私人决赛由特伯弗出局;
private final ByteBuffer inBuffer=ByteBuffer.allocateDirect(1024);
私人最终int msgSize;
私有最终StringBuilder sb=新StringBuilder(1024);
私有整数间隔;
私密信息;
私人长途旅行;
私有int mod;
公共客户端(字符串主机、int端口、int msgSize)引发IOException{
this.socketChannel=socketChannel.open();
this.host=host;
this.port=端口;
this.exputffer=ByteBuffer.allocateDirect(msgSize);
this.msgSize=msgSize;
对于(inti=0;i
我执行
java-server-cp。服务器
java-Server-cp。客户端
。客户端的输出为:


根据@dunni请求,更改为1秒延迟,而不是30秒延迟。同样的问题:
您遇到的一个问题是,当没有数据可读取时,JVM、CPU及其缓存正在休眠。一旦这个
import java.util.concurrent.TimeUnit;

public class Locker implements Runnable {

private static final int WARMUP = 40000;

private final Object readLock = new Object();
private final Object writeLock = new Object();
private final Object stateLock = new Object();

private final StringBuilder sb = new StringBuilder(1024);

private long interval;
private int totalMessagesSent;
private long timeSent;
private int mod;
private long totalOps;
private long readerThread;
private long writerThread;


public Locker() {
    this.interval = 1;
    this.mod = 20000;
}

public static long busySleep(long t) throws InterruptedException {
    long until = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(t);
    while(System.nanoTime() < until);
    return until;
}

public void start() throws Exception {
    Thread t = new Thread(this);
    t.start();
}

private final void printResults(long latency, long timeToRead) {
    sb.setLength(0);
    sb.append(new java.util.Date().toString());
    sb.append(" Results: totalMessagesSent=").append(totalMessagesSent);
    sb.append(" currInterval=").append(interval);
    sb.append(" latency=").append(latency);
    sb.append(" timeToRead=").append(timeToRead);
    sb.append(" totalOps=").append(totalOps);
    sb.append(" reader=").append(readerThread);
    sb.append(" writer=").append(writerThread);
    System.out.println(sb);
}

@Override
public void run() {

    try {
        while(true) {

            busySleep(interval);

            timeSent = System.nanoTime();

            try {
                synchronized (writeLock) {
                    synchronized (stateLock) {
                        writerThread = Thread.currentThread().getId();
                    }
                    totalOps++;
                }
            }
            finally {
                synchronized (stateLock) {
                    writerThread = 0;
                }
            }

            long timeToRead = System.nanoTime();

            try {
                synchronized (readLock) {
                    synchronized (stateLock) {
                        readerThread = Thread.currentThread().getId();
                    }
                    totalOps++;
                }
            } finally {
                synchronized (stateLock) {
                    readerThread = 0;
                }
            }

            long now = System.nanoTime();

            timeToRead = now - timeToRead;

            long latency = now - timeSent;

            if (++totalMessagesSent % mod == 0 || totalMessagesSent == 1) {
                printResults(latency, timeToRead);
            }

            if (totalMessagesSent == WARMUP) {
                this.interval = 5000;
                this.mod = 1;
            }
        }

    } catch(Exception e) {
        throw new RuntimeException(e);
    }
}

public static void main(String[] args) throws Exception {
    Locker locker = new Locker();
    locker.start();
}
}
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

public class Locker {
    static final int WARMUP = 20000;
    final Object readLock = new Object();
    final Object writeLock = new Object();
    final Object stateLock = new Object();

    long interval = 1;
    int totalMessagesSent;
    long totalOps;
    long readerThread;
    long writerThread;
    final long[] measures = new long[WARMUP + 20];

    static long busySleep(long t) {
        long until = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(t);
        while(System.nanoTime() < until);
        return until;
    }
    void printResults(long latency, long timeToRead) {
        if (readerThread != 0 || writerThread != 0 || totalMessagesSent  > totalOps || timeToRead < 0) throw new Error();
        measures[totalMessagesSent] = latency;
    }

    void run() {
        while(totalMessagesSent < measures.length) {
            busySleep(interval);
            long timeSent = System.nanoTime();
            try {
                synchronized (writeLock) {
                    synchronized (stateLock) {
                        writerThread = Thread.currentThread().getId();
                    }
                    totalOps++;
                }
            }
            finally {
                synchronized (stateLock) {
                    writerThread = 0;
                }
            }
            long timeToRead = System.nanoTime();
            try {
                synchronized (readLock) {
                    synchronized (stateLock) {
                        readerThread = Thread.currentThread().getId();
                    }
                    totalOps++;
                }
            } finally {
                synchronized (stateLock) {
                    readerThread = 0;
                }
            }
            long now = System.nanoTime();
            timeToRead = now - timeToRead;
            long latency = now - timeSent;
            printResults(latency, timeToRead);
            ++totalMessagesSent;
            this.interval = (totalMessagesSent/WARMUP * 5000) + 1;
        }
        System.out.println("last measures = " + Arrays.toString(Arrays.copyOfRange(measures, WARMUP - 20, measures.length - 1)));
    }

    public static void main(String[] args) {
        new Locker().run();
    }
}