-
Notifications
You must be signed in to change notification settings - Fork 592
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
IConnection.CreateModel() is significantly slower in 6.1.0. #860
Comments
Please share a benchmark snippet we can use to reproduce. We try to minimize guessing and implicit assumptions when reasoning about library behavior. Acquiring and releasing a lock around an operation will not make it more efficient. |
Ideally, a traffic capture should be taken and shared along with an executable way to run the benchmark. The latency of the method in question is highly dependent on the network. |
Please share a traffic capture and a complete set of code we can compile and run to observe this behavior. If we find a regression, I will re-open this issue. |
Snippet as follows:
|
What is the core count on the machine you are using? If you add |
Re-opening since we received code to try and reproduce. |
|
@stebet @makercob this version consistently performs well using both https://github.com/lukebakken/rabbitmq-dotnet-client-860/blob/main/Program.cs Main differences:
|
Here's another interesting thing I found. If you apply #863 (which removes https://github.com/lukebakken/rabbitmq-dotnet-client-860/blob/main/Program.cs Note that the above adds I hope that @stebet or @danielmarbach can explain this 😂 |
Try calling .ToArray() on the end of the LINQ statement in the current code and see if that changes anything. It's possible that Task.WhenAll iterates through the loop taking only X tasks at a time, and therefore a new task isn't started until the previous one finishes, where a ToArray will evaluate the entire enumeration before calling Task.WhenAll, hopefully scheduling all the tasks immediately. |
@stebet as you suspected calling I won't close this issue (#860) because it does demonstrate a problem that is resolved by #863. @makercob please take the time to test the workarounds discussed in the recent comments. Thanks. |
@lukebakken I doubt it is a good idea to add guidance around setting min threads. How would you ever come up with good guidance to guide the users to set appropriate values? You as a library can't really make any assumptions about the nature of threading involved by the code that is calling you. The problem I see here is the fact that even-though we have an IO-bound path we can't really leverage async here because the API surface is sync. Because the API is sync anyone that calls it and wants to do it in parallel has to offload the calls explicitly to the worker thread pool. Explicit offloading to the worker threadpool increases the pressure on the pool and might cause it to ramp up it's capacity (also known as hill climbing). That operation can cause significant stalls depending on the workload. And the library in addition to that yielding internally increases the pressure even more. That's why you see an improvement when setting the min threads because the thread pool will likely already be ready to handle the workload that is demanded in the sample and removing the yield causes less stress. So removing the yield didn't make it into 6.1? |
Thanks for the input. There were enough caveats in your comment here that I didn't remove the yield call for |
@lukebakken Here are my findings, on a 4-core machine: LINQ is used, not for loop. with 6.1.0
with 6.0.0
|
My tests show that this issue can be fixed via the code changes suggested in the comments as well as #863. I will produce |
@lukebakken Updated to 6.1.1-rc.1, however, the issue still persists. |
@makercob this is open source software. You are welcome to profile your workload with both versions and share both results. |
@makercob in my environment where I could reproduce the issue, the issue is fixed. "the issue still persists" does not give us actionable information. At the very least, provide an exact copy of the code you are running. Note that calling |
Updated this client from 6.0.0 to 6.1.0, and noticed that IConnection.CreateModel() becomes significantly slower.
Environments and preconditions:
Symptoms:
When creating IModel, the initial 2 or 3 invoking are pretty quick, each taking about 40ms (WAN connection), however succeeding attempts become much slower, taking up to 1,000ms for each.
And also, putting lock(_lockObject) { ... } around IConnection.CreateModel() just makes it even slower.
The text was updated successfully, but these errors were encountered: