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);
                }
            );