我收到了大量的邮件,我想让我的ReceivedCallBack更有效率。
我正在使用一些方便的字符串处理 - 但有更快的方法吗?
public class StateObject
{
public Socket socket = null;
public const int BufferSize = 256;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
public string SessionID()
{
return socket.Handle.ToString();
}
}
public void ReceivedCallBack(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket socket = state.socket;
try
{
int bytesRead = socket.EndReceive(ar);
if (bytesRead > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
string[] contents = state.sb.ToString().Split('@');
int delimCount = state.sb.ToString().Count(x => x == '@');
for (int d = 0; d < delimCount; d++)
{
if (contents[d] != "")
OnMessage(state, contents[d]);
}
if (!state.sb.ToString().EndsWith("@"))
{
state.sb.Clear();
state.sb.Append(contents[contents.Count() - 1]);
}
else
{
state.sb.Clear();
}
socket.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None, new AsyncCallback(ReceivedCallBack), state);
}
else
{
// If no data was recieved then the connection is probably dead
OutputWriteLine("Client " + state.SessionID() + " disconnected");
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Unusual error during Receive!");
}
}
答案 0 :(得分:2)
这里存在一个根本问题:当你处理当前的套接字时,你将没有缓冲区。内核可能丢弃数据包,导致重试。对于高吞吐量,您应该在处理完成的缓冲区之前发布多个缓冲区并立即重新发布新的空缓冲区。现在说,用多个缓冲区实现正确的处理非常很难,因为你必须跟踪发布的订单,你必须小心处理不完整的消息(你不能重新发布一个部分填充的缓冲区用于消息的“其余”,因为已经发布了缓冲区)。阅读High Performance Windows programs处链接的文章了解更多详情。
现在,使用您拥有的代码:对其进行分析。从Beginners Guide to Performance Profiling开始。我怀疑你会发现通常的罪魁祸首(例如\s
中的分配),但我建议你衡量自己,找到瓶颈,然后再进行更改。
对于字符串处理,请阅读以下经典之作:why GNU grep is fast(尽管使用Boyer-Moore搜索单个string.Split()
不会那么有影响力。如果可能,请考虑将协议更改为更友好的解析(例如,二进制proto buff)。
答案 1 :(得分:1)
字符串处理确实非常低效。每条消息的分配,LINQ和二次处理成本。此外,调用sb.ToString
3次也无济于事。
将应用程序置于满负荷状态并对此代码进行分析,以查看是否需要对其进行优化。如果是的话,你可能应该首先应用一些简单的修复,并解决我提到的问题。
通常,您可能不应该编写自己的(基于ASCII的)网络协议。只需使用现成的东西,如WCF,HTTP或protobuf。