[英]SocketChannel.write() throwing OutOfMemoryError when attempting to write large buffer
[英]socketchannel.write() becomes very slow when message size is large
在我使用java nio的程序中,當嘗試連續寫入10 KB消息時,socketchannel.write()變得非常慢。 編寫完整的10 KB消息的時間為160毫秒至200毫秒。 但是,編寫完整的5 KB消息所需的時間僅為0.8 ms。
在選擇器中,我只有Selection.OP_READ,不處理Selection.OP_WRITE。 接收到較大的完整消息時,會將其寫入另一個接收者4次。
有人會問同樣的問題嗎? 有一篇關於socketchannel.write()的文章。 我的問題是如何在OP_READ和OP_WRITE之間交替更改?
如果添加一個例如150 ms的間隔,則響應時間會縮短。 有什么辦法可以找到緩沖區何時已滿,以便讓程序等待。 我的操作系統是Windows XP。
謝謝。
我通過檢查寫入的字節數來遵循EPJ的建議。 但是響應時間仍然很高。 我在這里發布了部分代碼,並想檢查我的代碼是否有問題。
//這是使用nio的writeData()部分:
while (buffer.hasRemaining()) {
try {
buffer.flip();
n = socket.write(buffer);
if(n == 0) {
key.interestOps(SelectionKey.OP_WRITE);
key.attach(buffer);
break;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
buffer.compact();
}
}
if(buffer.position()==0) {
key.interestOps(SelectionKey.OP_READ);
}
我建議您的讀取過程很慢,這將導致其接收緩沖區備份,這將導致您的發送緩沖區備份,從而使發送停止。
否則,您沒有為非阻塞模式正確編寫代碼。 如果從write()方法得到的結果為零,則必須(a)將interestOps更改為OP_WRITE,並且(b)返回到select循環。 當您獲得OP_WRITE時,您必須重復寫入操作; 如果您寫入了所有數據,則將interestOps改回OP_READ,否則將所有內容保持不變,並等待下一個OP_WRITE。 如果您嘗試在非阻塞模式下進行寫操作時進行循環,即使存在零長度寫操作,您也只會旋轉,從而浪費了CPU周期和時間。
模組錯誤:
while (buffer.position() > 0)
{
try
{
buffer.flip();
int count = ch.write(buffer);
if (count == 0)
{
key.interestOps(SelectionKey.OP_WRITE);
break;
}
}
finally
{
buffer.compact();
}
}
if (buffer.position() == 0)
{
key.interestOps(SelectionKey.OP_READ);
}
如果寫入時間超過20微秒,則建議您遇到緩沖區已滿的問題。 我假設您正在使用阻止NIO。 當發送緩沖區未滿時,通常需要5到20微秒。 過去,我已將服務器配置為殺死需要2毫秒寫入時間的所有慢速消耗者。 (可能有點激進。)
您可以嘗試增加發送緩沖區的大小(Socket.setSendBufferSize(int),該屬性也可用於SocketChannels),但是看來您正在嘗試發送的數據超出了帶寬的允許范圍。
10 KB不是一條大消息,典型的發送緩沖區大小是64 KB,因此要使其滿,您將需要發送6-7條消息。 這可以解釋5KB的方式相對較快。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.