Skip to content

Commit 8475e65

Browse files
committed
Recycle json writers
1 parent ffd4101 commit 8475e65

File tree

3 files changed

+93
-15
lines changed

3 files changed

+93
-15
lines changed

Telegram/Common/ArrayPoolBufferWriter.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace Telegram.Common
1818
/// </summary>
1919
public sealed class ArrayPoolBufferWriter : IBufferWriter<byte>, IDisposable
2020
{
21-
private const int DefaultInitialCapacity = 256;
21+
private const int DefaultInitialCapacity = 16 * 1024;
2222
private const int MaxArrayLength = 0x7FFFFFC7; // Array.MaxLength
2323

2424
private readonly ArrayPool<byte> _pool;
@@ -437,5 +437,23 @@ public void Dispose()
437437
_buffer = null!;
438438
_disposed = true;
439439
}
440+
441+
public void Rent()
442+
{
443+
if (_buffer != null)
444+
return;
445+
446+
_buffer = _pool.Rent(DefaultInitialCapacity);
447+
}
448+
449+
public void Reset()
450+
{
451+
if (_buffer == null)
452+
return;
453+
454+
_pool.Return(_buffer);
455+
_buffer = null!;
456+
_index = 0;
457+
}
440458
}
441459
}

Telegram/Td/Client.cs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,22 @@ public unsafe void Send(Function function, ClientResultHandler handler = null)
7575
_handlers[requestId] = handler;
7676
}
7777

78-
using var buffer = new ArrayPoolBufferWriter();
78+
if (_writer == null)
79+
{
80+
_writer = new ArrayPoolBufferWriter();
81+
}
82+
else
83+
{
84+
_writer.Rent();
85+
}
7986

80-
var request = ClientJson.ToJson(buffer, function, requestId);
87+
var request = ClientJson.ToJson(_writer, function, requestId);
8188
fixed (byte* bytes = request)
8289
{
8390
td_send(_clientId, bytes);
8491
}
92+
93+
_writer.Reset();
8594
}
8695

8796
/// <summary>
@@ -92,9 +101,16 @@ public unsafe void Send(Function function, ClientResultHandler handler = null)
92101
/// <exception cref="NullReferenceException">Thrown when query is null.</exception>
93102
public static unsafe Object Execute(Function function)
94103
{
95-
using var buffer = new ArrayPoolBufferWriter();
104+
if (_writer == null)
105+
{
106+
_writer = new ArrayPoolBufferWriter();
107+
}
108+
else
109+
{
110+
_writer.Rent();
111+
}
96112

97-
var request = ClientJson.ToJson(buffer, function, 0);
113+
var request = ClientJson.ToJson(_writer, function, 0);
98114
fixed (byte* source = request)
99115
{
100116
var ptr = td_execute(source);
@@ -111,15 +127,23 @@ public static unsafe Object Execute(Function function)
111127
return null;
112128
}
113129

114-
buffer.Resize(length);
130+
_writer.Resize(length);
115131

116-
fixed (byte* dest = buffer.Bytes)
132+
fixed (byte* dest = _writer.Bytes)
117133
{
118-
Buffer.MemoryCopy(ptr, dest, buffer.Bytes.Length, length);
134+
Buffer.MemoryCopy(ptr, dest, _writer.Bytes.Length, length);
119135
}
120136

121-
var span = new ReadOnlySpan<byte>(buffer.Bytes, 0, buffer.Bytes.Length);
122-
return ClientJson.FromJson(span, out _, out _);
137+
var span = new ReadOnlySpan<byte>(_writer.Bytes, 0, length);
138+
139+
try
140+
{
141+
return ClientJson.FromJson(span, out _, out _);
142+
}
143+
finally
144+
{
145+
_writer.Reset();
146+
}
123147
}
124148
}
125149

@@ -153,6 +177,8 @@ public static void Run()
153177
}
154178
}
155179

180+
[ThreadStatic]
181+
private static ArrayPoolBufferWriter _writer;
156182
private static byte[] _buffer = new byte[1 << 18];
157183

158184
public static unsafe Object Receive(double timeout, out int clientId, out long requestId)
@@ -188,7 +214,7 @@ public static unsafe Object Receive(double timeout, out int clientId, out long r
188214
Buffer.MemoryCopy(ptr, dest, _buffer.Length, length);
189215
}
190216

191-
var span = new ReadOnlySpan<byte>(_buffer, 0, _buffer.Length);
217+
var span = new ReadOnlySpan<byte>(_buffer, 0, length);
192218
return ClientJson.FromJson(span, out clientId, out requestId);
193219
}
194220

Telegram/Td/ClientJson.cs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77

88
using System;
9+
using System.Buffers;
910
using System.Buffers.Text;
1011
using System.Collections.Generic;
1112
using System.ComponentModel;
@@ -47,14 +48,47 @@ public partial class ClientJson
4748
SkipValidation = true
4849
};
4950

51+
[ThreadStatic]
52+
private static Utf8JsonWriter? _writer;
53+
54+
[ThreadStatic]
55+
private static FreeBufferWriter? _buffer;
56+
57+
private class FreeBufferWriter : IBufferWriter<byte>
58+
{
59+
public void Advance(int count)
60+
{
61+
// Do nothing
62+
}
63+
64+
public Memory<byte> GetMemory(int sizeHint = 0)
65+
{
66+
return Memory<byte>.Empty;
67+
}
68+
69+
public Span<byte> GetSpan(int sizeHint = 0)
70+
{
71+
return Span<byte>.Empty;
72+
}
73+
}
74+
5075
public static ReadOnlySpan<byte> ToJson(ArrayPoolBufferWriter buffer, Function obj, long requestId)
5176
{
52-
using (var writer = new Utf8JsonWriter(buffer, _options))
77+
if (_writer == null)
5378
{
54-
writer.WriteStartObject();
55-
obj.ToJson(writer);
56-
writer.WriteEndObject();
79+
_writer = new Utf8JsonWriter(buffer, _options);
80+
_buffer = new();
5781
}
82+
else
83+
{
84+
_writer.Reset(buffer);
85+
}
86+
87+
_writer.WriteStartObject();
88+
obj.ToJson(_writer);
89+
_writer.WriteEndObject();
90+
_writer.Flush();
91+
_writer.Reset(_buffer);
5892

5993
if (requestId != 0)
6094
{

0 commit comments

Comments
 (0)