Multithreading QueueUtil为MessageHandler生成太多线程,异步/等待问题
更新: 错误在于对实际任务使用Multithreading QueueUtil为MessageHandler生成太多线程,异步/等待问题,multithreading,azure,async-await,azureservicebus,azure-servicebus-queues,Multithreading,Azure,Async Await,Azureservicebus,Azure Servicebus Queues,更新: 错误在于对实际任务使用Action onSuccess并在没有wait的情况下调用它。实际上,我们正在将一个async回调作为onSuccess传递,因此它没有阻塞,只是在不等待的情况下被激发。将类型更改为Func并通过await onSuccess(messageObj)调用修复了该行为 我正在接收消息,每个消息都由一个长时间运行的作业处理,该作业涉及IO和CPU密集型例程。我的问题是,我注册的消息处理程序被调用的次数太多(基本上与消息的调用次数相同),这使得我的进程消耗了100%的C
Action onSuccess
并在没有wait
的情况下调用它。实际上,我们正在将一个async
回调作为onSuccess传递,因此它没有阻塞,只是在不等待的情况下被激发。将类型更改为Func
并通过await onSuccess(messageObj)
调用修复了该行为
我正在接收消息,每个消息都由一个长时间运行的作业处理,该作业涉及IO和CPU密集型例程。我的问题是,我注册的消息处理程序被调用的次数太多(基本上与消息的调用次数相同),这使得我的进程消耗了100%的CPU资源,并且所有的事情都慢得可怕
我的客户有一个包装器,我想我因此陷入了麻烦。
我知道我的代码是错误的,但我对async/await在.NET中的工作方式缺乏足够的了解,无法自己修复它
这是包装器代码,它获取json消息或Azure存储的链接,因此它处理此逻辑并将其传递给回调
public static void RegisterReceiver(string queueName,
Action<QueueMessage> onSuccess, Action<ExceptionReceivedEventArgs> onError)
_queueClient.RegisterMessageHandler(
async (message, cancellationToken) =>
{
var messageObj = new QueueMessage(message);
var regex = new Regex(@"\[blob%([^\]]+)\](.+)");
if (regex.IsMatch(messageObj.Body))
{
// Pulling blob data from storage
var match = regex.Match(messageObj.Body);
messageObj.ContentType = match.Groups[1].Value;
messageObj.Body = await BlobUtil.GetAndDeleteBlobAsync(match.Groups[2].Value, settings.QueueBlobStorageName);
}
onSuccess(messageObj);
},
new MessageHandlerOptions((exceptionArgs) =>
{
onError(exceptionArgs);
return Task.CompletedTask;
})
{
MaxConcurrentCalls = 1
}
);
因此,不知何故,对于所有这些异步/等待的事情,我的接收者只是在消息到达时不断生成线程。错误在于对实际任务使用
Action-onSuccess
并在没有wait
的情况下调用它。实际上,我们正在将一个async
回调作为onSuccess传递,因此它没有阻塞,只是在不等待的情况下被激发。将类型更改为Func
并通过await onSuccess(messageObj)
调用修复了该行为。错误在于对实际任务使用Action onSuccess
并在不使用await
的情况下调用它。实际上,我们正在将一个async
回调作为onSuccess传递,因此它没有阻塞,只是在不等待的情况下被激发。将类型更改为Func
并通过wait onSuccess(messageObj)
调用,修复了该行为。处理程序将运行5分钟,如果处理未完成,将重新传递消息进行处理。我不太明白您的抽象在哪里被调用,以及它在Azure中是如何被托管的,但是对于收到的每一条消息,都应该调用消息处理程序。而注册应该只进行一次。它通过kestrel(dotnet My.dll)托管在VM上。问题是我的processService.RunJobs(消息)
立即被调用多次(基本上与消息的次数相同),这与每个MaxConcurrentCalls选项只生成一个消息处理程序的预期行为相反。这听起来很不对。你能分享一个复制程序的链接吗?我会尝试给出我们代码的简化版本。@SeanFeldman,在为你复制我的项目中的所有内容之后,我发现了一个错误。我们错误地使用了void操作而不是waitiable Func,这导致我们的任务在没有等待的情况下运行。我将更新这个问题,我想它应该被关闭,毕竟它与服务总线无关。处理程序将运行5分钟,如果处理未完成,消息将被重新传递以进行处理。我不太明白您的抽象在哪里被调用,以及它在Azure中是如何被托管的,但是对于收到的每一条消息,都应该调用消息处理程序。而注册应该只进行一次。它通过kestrel(dotnet My.dll)托管在VM上。问题是我的processService.RunJobs(消息)
立即被调用多次(基本上与消息的次数相同),这与每个MaxConcurrentCalls选项只生成一个消息处理程序的预期行为相反。这听起来很不对。你能分享一个复制程序的链接吗?我会尝试给出我们代码的简化版本。@SeanFeldman,在为你复制我的项目中的所有内容之后,我发现了一个错误。我们错误地使用了void操作而不是waitiable Func,这导致我们的任务在没有等待的情况下运行。我会更新这个问题,我想它应该被关闭,毕竟它与服务巴士无关。是的,那就行了是的,那就行了
QueueUtil.RegisterReceiver(QueueUtil.QUEUE_NAME,
async message =>
{
await processService.RunJobs(message);
},
exceptionArgs =>
{
throw new Exception("Exception occurred while receiving message from " + QueueUtil.QUEUE_NAME,
exceptionArgs.Exception);
}
);