我有很多不同的端口要侦听,并迭代可用的数据发送到Dataflow管道。我总共监听了14个端口。我正在寻找关于如何减少以下代码的CPU使用的任何建议。
我只是将端口传递给一个方法,然后将它们添加到一个列表中:
public static void AddPorts(Dictionary<int,string> ports)
{
try
{
var NewEndPoints = new List<IPEndPoint>();
foreach (var port in ports)
{
var endpoint = new IPEndPoint(IPAddress.Any, port.Key);
NewEndPoints.Add(endpoint);
if (!Endpoints.Contains(endpoint))
{
Endpoints.Add(endpoint);
var client = new UdpClient(endpoint);
logger.Info("New Client added on port: {0}", endpoint.Port);
Clients.Add(client);
}
else
{
if (IgnoredPorts.Contains(endpoint.Port))
{
logger.Info("Existing client enabled on port: {0}", endpoint.Port);
IgnoredPorts.Remove(port.Key);
}
}
}
var differences = Endpoints.Except(NewEndPoints);
differences.ToList().ForEach(d =>
{
if (!IgnoredPorts.Contains(d.Port))
{
IgnoredPorts.Add(d.Port);
logger.Info("Client removed on port: {0}", d.Port);
}
});
}
catch (Exception ex)
{
logger.Error("Error creating udpclients", ex);
}
}然后,我对任何可用的数据迭代套接字。
Task.Run(async delegate
{
while (Receive)
{
try
{
// get any channels that have data availble
// Iterate over the the channels and send to Dataflow pipeline
var readyChannels =
(from channel in Clients
where channel.Available > 0 && !ListenersDF.IgnoredPorts.Contains(((IPEndPoint)channel.Client.LocalEndPoint).Port)
select channel);
// Iterate over the the channels and send to Dataflow pipeline
foreach (var channel in readyChannels)
{
// await on the result of the task
await ReceiveAndRespond(channel);
}
}
catch (Exception ex)
{
logger.Error("Error sending packet to bufferBlock", ex);
}
}
});并最终将其发送到TPL数据流线。
async Task ReceiveAndRespond(UdpClient channel)
{
UdpReceiveResult? result = null;
try
{
result = await channel.ReceiveAsync();
}
catch (Exception exc)
{
logger.Error("Error receiving from channel: " + exc.Message, exc);
}
if (result != null)
{
var device = (from d in Ports
where d.Key == ((IPEndPoint)channel.Client.LocalEndPoint).Port
select d.Value).FirstOrDefault();
UdpData data = new UdpData() { Client = channel, Data = result.Value.Buffer, LocalPort = ((IPEndPoint)channel.Client.LocalEndPoint).Port, LocalIP = ((IPEndPoint)channel.Client.LocalEndPoint).Address, RemoteEndpoint = result.Value.RemoteEndPoint, Device = device };
Flow.bufferBlock.Post(data);
// for testing logs the hex string to a log file
//logger.Warn(string.Format("Data received on port: {0} for device: {1} with data: {2}", data.LocalPort, data.Device, data.Data.ByteArrayToHexString()));
}
}然后CPU坐在50%,几乎没有任何流量,我肯定有一些性能有待提高,只是不确定在哪里。
发布于 2015-02-28 14:11:29
请注意,Endpoints.Contains(endpoint)永远不会是真,因为您创建了一个新的IPEndPoint,并且它没有实现IEquatable接口。
除了@mjolka描述了为什么您有50%的CPU负载,我想建议您如何避免它。
目前,您有一个中央位置,可以在一个地方管理所有套接字。我建议采取不同的做法-让每个端点单独处理数据,并将所有套接字仅作为正在进行的处理(任务)的集合来管理,如下所示:
public async Task RunListenerAsync(int port)
{
var endpoint = new IPEndPoint(IPAddress.Any, port);
using (var client = new UdpClient(endpoint))
{
while (true)
{
try
{
var result = await client.ReceiveAsync().ConfigureAwait(false);
ProcessEndpointData(client, result);
}
catch (Exception exc)
{
logger.Error("Error receiving from channel: " + exc.Message, exc);
return;
}
}
}
}
private void ProcessEndpointData(UdpClient client, UdpReceiveResult result)
{
var localEndPoint = (IPEndPoint)client.Client.LocalEndPoint;
var device = (from d in Ports
where d.Key == localEndPoint.Port
select d.Value).FirstOrDefault();
var data = new UdpData
{
Client = client,
Data = result.Buffer,
LocalPort = localEndPoint.Port,
LocalIP = localEndPoint.Address,
RemoteEndpoint = result.RemoteEndPoint,
Device = device
};
Flow.bufferBlock.Post(data);
}注意,在这个实现中,停止侦听端口的唯一方法是在await client.ReceiveAsync()上获得一个异常。您可能需要引入CancellationToken来控制何时停止此进程。
使用这种方法,所有端口的注册和侦听将非常简单,如:
public Task ListenPortsAsync(IEnumerable<int> ports)
{
return Task.WhenAll(ports.Select(RunListenerAsync));
}发布于 2015-02-27 03:13:05
这并不奇怪,CPU使用率是50%,它看起来你在忙-等待。
同时(接收){尝试{ var readyChannels =.(readyChannels中的var通道){.}捕获(异常ex) {.}}
来自维基百科,
在软件工程中,忙碌等待或旋转是一种技术,在这种技术中,进程反复检查某个条件是否为真,例如键盘输入或锁是否可用。..。在某些情况下,旋转是一个有效的策略.然而,一般来说,旋转被认为是一种反模式,应该避免,因为可以用来执行不同任务的处理器时间被浪费在无用的活动上。
您将希望重组您的程序,以便可以删除该循环。
https://codereview.stackexchange.com/questions/82697
复制相似问题