-
Notifications
You must be signed in to change notification settings - Fork 60
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
Use string.Create when building a new inbox string #551
Conversation
We have |
Great, then it's covered :) There are two other places I found that could be optimized in a similar way, but I'm not sure if they are hot enough to justify the From 6f061898810a4fb923882ee8b4bb07ba77c3bbbc Mon Sep 17 00:00:00 2001
From: jasper-d <jasper-d@users.noreply.github.com>
Date: Wed, 10 Jul 2024 20:43:11 +0200
Subject: [PATCH] Allocate less
---
src/NATS.Client.Core/Internal/NuidWriter.cs | 15 ++++++----
.../NatsJSContext.Consumers.cs | 29 +++++++++++++++++--
2 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/src/NATS.Client.Core/Internal/NuidWriter.cs b/src/NATS.Client.Core/Internal/NuidWriter.cs
index e8a5785..30edeee 100644
--- a/src/NATS.Client.Core/Internal/NuidWriter.cs
+++ b/src/NATS.Client.Core/Internal/NuidWriter.cs
@@ -54,13 +54,16 @@ internal sealed class NuidWriter
public static string NewNuid()
{
- Span<char> buffer = stackalloc char[22];
- if (TryWriteNuid(buffer))
+#if NET6_0_OR_GREATER || NETSTANDARD2_1
+ return string.Create((int)NuidLength, default(object), (buffer, _) =>
{
- return buffer.ToString();
- }
-
- throw new InvalidOperationException("Internal error: can't generate nuid");
+ TryWriteNuid(buffer);
+ });
+#else
+ Span<char> buffer = stackalloc char[(int)NuidLength];
+ TryWriteNuid(buffer);
+ return buffer.ToString();
+#endif
}
private static bool TryWriteNuidCore(Span<char> buffer, Span<char> prefix, ulong sequential)
diff --git a/src/NATS.Client.JetStream/NatsJSContext.Consumers.cs b/src/NATS.Client.JetStream/NatsJSContext.Consumers.cs
index 45a7864..384d36d 100644
--- a/src/NATS.Client.JetStream/NatsJSContext.Consumers.cs
+++ b/src/NATS.Client.JetStream/NatsJSContext.Consumers.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using System.Runtime.CompilerServices;
using NATS.Client.Core.Internal;
using NATS.Client.JetStream.Models;
@@ -228,8 +229,32 @@ public partial class NatsJSContext : INatsJSContext
request.Config.FilterSubjects = opts.FilterSubjects;
}
- var name = NuidWriter.NewNuid();
- var subject = $"{Opts.Prefix}.CONSUMER.CREATE.{stream}.{name}";
+#if NET6_0_OR_GREATER || NETSTANDARD2_1
+ // This could also be written like this to avoid the extra string alloc
+ // from NuidWriter.NewNuid at the costs of being ~2x as slow as
+ // string.Create.
+ //
+ // Span<char> nuid = stackalloc char[(int)NuidWriter.NuidLength];
+ // NuidWriter.TryWriteNuid(nuid);
+ // var subject = $"{Opts.Prefix}.CONSUMER.CREATE.{stream}.{nuid}";
+ const string consumerCreate = ".CONSUMER.CREATE.";
+ var len = consumerCreate.Length + (int)NuidWriter.NuidLength + stream.Length + Opts.Prefix.Length;
+
+ var subject = string.Create(len, (Opts.Prefix, stream), static (buffer, state) =>
+ {
+ state.Prefix.AsSpan().CopyTo(buffer);
+ var remaining = buffer.Slice(state.Prefix.Length);
+ consumerCreate.AsSpan().CopyTo(remaining);
+ remaining = remaining.Slice(consumerCreate.Length);
+ state.stream.AsSpan().CopyTo(remaining);
+ remaining = remaining.Slice(state.stream.Length);
+ var didWrite = NuidWriter.TryWriteNuid(remaining);
+ Debug.Assert(remaining.Length == NuidWriter.NuidLength, "remaining.Length == NuidWriter.NuidLength");
+ });
+#else
+ var nuid = NuidWriter.NewNuid();
+ var subject = $"{Opts.Prefix}.CONSUMER.CREATE.{stream}.{nuid}";
+#endif
return JSRequestResponseAsync<ConsumerCreateRequest, ConsumerInfo>(
subject: subject,
--
2.45.2 |
yeah I think so too ;)
I can't see them being on a hot path, maybe |
Let's keep it the way it is then. You'll have to maintain it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM thanks @jasper-d
* Handle various protocol errors and socket exceptions (#584) * Fetch idle timeout default fix (#582) * Obj store empty list fixed (#578) * KV never set duplicate window (#577) * Resolved issue of ObjStore GetInfo MTime returning 0 (#567) * Add logging enhancements and improve error handling (#570) * Base64 Encoding simplification + optimization (#549) * Use string.Create when building a new inbox string (#551)
* Handle various protocol errors and socket exceptions (#584) * Fetch idle timeout default fix (#582) * Obj store empty list fixed (#578) * KV never set duplicate window (#577) * Resolved issue of ObjStore GetInfo MTime returning 0 (#567) * Add logging enhancements and improve error handling (#570) * Base64 Encoding simplification + optimization (#549) * Use string.Create when building a new inbox string (#551)
Use a more idiomatic implementation for
NewInbox
and improve performance.Looks like tests target .NET6/8 only. I think that the NETSTANDARD2_0 path works too, but I don't have a setup to test that 🤞
6299995 is only tangentially related but I thought I could sneak it in.