-
Notifications
You must be signed in to change notification settings - Fork 598
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Minor improvements and optimizations #842
Conversation
Hello, thanks for taking the time to do this. What is the best way to prove that these changes have a positive effect on performance or other metric? |
Excellent question, difficult to answer. If there isn't a performance benchmark suite we can run, best I can do is some micro benchmarks: For Interface vs Class
|
And for IList
|
I'm liking this a lot. I have another PR coming as well, which avoid even more allocations as well. In the meantime, here is my oh-so-simple benchmark app. using System;
using System.Threading;
using System.Threading.Tasks;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace DeadlockRabbitMQ
{
class Program
{
private static int messagesSent = 0;
private static int messagesReceived = 0;
private static int batchesToSend = 100;
private static int itemsPerBatch = 500;
static async Task Main(string[] args)
{
ThreadPool.SetMinThreads(16 * Environment.ProcessorCount, 16 * Environment.ProcessorCount);
var connectionString = new Uri("amqp://guest:guest@localhost/");
var connectionFactory = new ConnectionFactory() { DispatchConsumersAsync = true, Uri = connectionString };
var connection = connectionFactory.CreateConnection();
var publisher = connection.CreateModel();
var subscriber = connection.CreateModel();
publisher.ConfirmSelect();
publisher.ExchangeDeclare("test", ExchangeType.Topic, false, false);
subscriber.QueueDeclare("testqueue", false, false, true);
var asyncListener = new AsyncEventingBasicConsumer(subscriber);
asyncListener.Received += AsyncListener_Received;
subscriber.QueueBind("testqueue", "test", "myawesome.routing.key");
subscriber.BasicConsume("testqueue", true, "testconsumer", asyncListener);
byte[] payload = new byte[512];
var batchPublish = Task.Run(() =>
{
while (messagesSent < batchesToSend * itemsPerBatch)
{
var batch = publisher.CreateBasicPublishBatch();
for (int i = 0; i < itemsPerBatch; i++)
{
var properties = publisher.CreateBasicProperties();
properties.AppId = "testapp";
properties.CorrelationId = Guid.NewGuid().ToString();
batch.Add("test", "myawesome.routing.key", false, properties, payload);
}
batch.Publish();
messagesSent += itemsPerBatch;
publisher.WaitForConfirmsOrDie();
}
});
var sentTask = Task.Run(async () =>
{
while (messagesSent < batchesToSend * itemsPerBatch)
{
Console.WriteLine($"Messages sent: {messagesSent}");
await Task.Delay(500);
}
Console.WriteLine("Done sending messages!");
});
var receivedTask = Task.Run(async () =>
{
while (messagesReceived < batchesToSend * itemsPerBatch)
{
Console.WriteLine($"Messages received: {messagesReceived}");
await Task.Delay(500);
}
Console.WriteLine("Done receiving all messages.");
});
await Task.WhenAll(sentTask, receivedTask);
publisher.Dispose();
subscriber.Dispose();
connection.Dispose();
Console.ReadLine();
}
private static Task AsyncListener_Received(object sender, BasicDeliverEventArgs @event)
{
Interlocked.Increment(ref messagesReceived);
return Task.CompletedTask;
}
}
} Edit: fixed a bug in the benchmarking code. |
Some of the changes here optimize methods that are never invoked on the hot code path (connection recovery is one example). Is it a worthwhile investment of our time, trying to squeeze a few nanoseconds in a loop here and a field there in such areas? |
I do not yet know which ones are used where, but then again, if there isn't a downside to it, faster is always better I guess. |
The downside to me is that the intent of a classic (indexed) Connection recovery runs no more often than once every 5 seconds by default, and quite often a few times in a given process' lifetime. |
The intent is certainly clearer in the foreach. Unfortunately for |
Fair enough, I don't feel too strongly about this. |
@bollhals can you please rebase this branch on top of |
a6b0919
to
d1f0e45
Compare
/done |
Backported to |
Proposed Changes
This PR contains various minor improvements I found while getting to know the code. The changes are in the areas of
Types of Changes
Checklist
CONTRIBUTING.md
documentFurther Comments
Publicly visible API is not touched at all. All I touched are internals, which I hope is fine.
Please let me know if this breaches some guideline or something.