【发布时间】:2022-01-19 02:17:15
【问题描述】:
我正在对消息传递服务器进行持续轮询。当消息到达服务器时,我抓取消息并处理它。不幸的是,这是一个简单的任务使用 80-100% 的 CPU。 更新:我已将其简化为 while 循环本身。 10 个任务中的 while 循环导致 CPU 以 100% 轻松达到最大值。
int i = 0;
while(true){
//At the start of every minute
if (DateTime.Now.Seconds == 0)
{
i++;
}
}
有没有一种方法可以限制循环,或者有更好更好的方法来编写此代码,使其不使用 100% 的 CPU?我曾尝试添加 1 秒的 Task.Delay,但这并没有多大帮助。
如果您能提供任何帮助或建议,我将不胜感激。
// First I poll 10 different locations for messages and each task polls its own queue
foreach(Queue queue in queueList)
{
task.Add(Task.Run(() => PollIndividualQueue(queue));
}
t= Task.WhenAll(task.ToArray()).WithAggregatedExceptions();
t.Wait();
//Then in the PollIndividualQueue method I implement the while loop that constantly polls a message queue for the next hour
private async Task<string> PollIndividualQueue(Queue queue)
{
var cancellationToken = new CancellationTokenSource(Timespan.FromMinutes(60)).Token;
while(!cancellationToken.IsCancellationRequested)
{
//Poll the queue and if there is a message grab it and process it
if(!await GetMessage())
{
//I call a stored procedure that inserts this message into the database.
using(var conn = new SqlConnection(...)
{
using(var cmd = new SqlCommand(MyStoredProc, conn)
{
cmd.CommandType = Command.StoredProcedure;
cmd.Parameters.Add(new SQlParameter(...InputMessage));
await conn.OpenAsync();
await cmd.ExecuteNonQueryAsync();
}
}
}
else
{
await Task.Delay(1000);
}
}
}
private Task<bool> getMessage(Queue queue)
{
object myLock = new object();
try
{
Monitor.Enter(myLock);
queue.Get(message);
}
catch(MQException ex)
{
if(ex.ReasonCode == 2033)
{
return false;
}
}
finally
{
Monitor.Exit(myLock);
}
}
编辑:谢谢大家的 cmets,但它似乎偏离了实际问题。问题是有没有办法使用总 CPU 的百分比? 我可以从字面上将所有这些代码从 While 循环中取出,并且 CPU 仍处于 100%。 while 循环似乎是驱动 CPU 负载的原因。
【问题讨论】:
-
你为什么要
Task.Run?就做task.Add(PollIndividualQueue(queue));为什么GetMessage不是异步的?if中的任何内容是异步的还是只是 CPU 密集型代码?你真的应该使用await而不是Wait()。 -
您的 getMessage 有问题,它使用了本地锁变量,并且没有相应的退出调用。
-
锁定一个局部变量是没有意义的。你永远不会与另一个线程竞争。
-
如果您不打算发布实际代码,或者至少是最低限度的复制,那么我们应该如何帮助您?如果你愿意,我可以做一些随机猜测,但它们不太可能有用。或者您可以发布
getMessage方法的其余部分,这可能是问题所在。 -
我建议您使用确实实现异步侦听器的 IBM MQ XMS.NET API。如果您想按照当前的方式执行此操作,则将接收器超时添加到您的 get 中,这将在返回 2033 之前等待消息到达队列的时间量,但一旦消息可用就会返回。
标签: c# loops task task-parallel-library ibm-mq