diff --git a/src/Discord.Net.Core/Discord.Net.Core.csproj b/src/Discord.Net.Core/Discord.Net.Core.csproj
index f5a86113d..bac6fd4e1 100644
--- a/src/Discord.Net.Core/Discord.Net.Core.csproj
+++ b/src/Discord.Net.Core/Discord.Net.Core.csproj
@@ -7,11 +7,11 @@
net45;netstandard1.1;netstandard1.3
-
-
+
+
-
+
diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs
index ab677c12b..f5e3e31b2 100644
--- a/src/Discord.Net.Rest/DiscordRestApiClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs
@@ -4,8 +4,6 @@ using Discord.Net;
using Discord.Net.Queue;
using Discord.Net.Rest;
using Discord.Serialization;
-using Discord.Serialization.Json;
-using Discord.Serialization.Json.Converters;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -13,7 +11,6 @@ using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
-using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Formatting;
@@ -31,7 +28,7 @@ namespace Discord.API
protected readonly SemaphoreSlim _stateLock;
protected readonly Serializer _serializer;
- protected readonly ConcurrentQueue _formatters;
+ protected readonly Pool _formatters;
private readonly RestClientProvider _restClientProvider;
protected bool _isDisposed;
@@ -56,7 +53,7 @@ namespace Discord.API
RequestQueue = new RequestQueue();
_stateLock = new SemaphoreSlim(1, 1);
- _formatters = new ConcurrentQueue();
+ _formatters = new Pool(() => new ArrayFormatter(128, SymbolTable.InvariantUtf8));
SetBaseUrl(DiscordConfig.APIUrl);
}
@@ -190,9 +187,8 @@ namespace Discord.API
options.HeaderOnly = true;
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
options.IsClientBucket = AuthTokenType == TokenType.User;
-
- if (!_formatters.TryDequeue(out var data))
- data = new ArrayFormatter(128, SymbolTable.InvariantUtf8);
+
+ var data = _formatters.Rent();
try
{
var request = new JsonRestRequest(RestClient, method, endpoint, SerializeJson(data, payload), options);
@@ -201,7 +197,7 @@ namespace Discord.API
finally
{
data.Clear();
- _formatters.Enqueue(data);
+ _formatters.Return(data);
}
}
@@ -244,8 +240,7 @@ namespace Discord.API
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
options.IsClientBucket = AuthTokenType == TokenType.User;
- if (!_formatters.TryDequeue(out var data))
- data = new ArrayFormatter(128, SymbolTable.InvariantUtf8);
+ var data = _formatters.Rent();
try
{
var request = new JsonRestRequest(RestClient, method, endpoint, SerializeJson(data, payload), options);
@@ -254,7 +249,7 @@ namespace Discord.API
finally
{
data.Clear();
- _formatters.Enqueue(data);
+ _formatters.Return(data);
}
}
diff --git a/src/Discord.Net.Rpc/DiscordRpcApiClient.cs b/src/Discord.Net.Rpc/DiscordRpcApiClient.cs
index 6c99e2fe3..0995fe2e7 100644
--- a/src/Discord.Net.Rpc/DiscordRpcApiClient.cs
+++ b/src/Discord.Net.Rpc/DiscordRpcApiClient.cs
@@ -225,8 +225,7 @@ namespace Discord.API
private async Task SendRpcAsyncInternal(string cmd, object payload, Optional evt, RequestOptions options)
where TResponse : class, new()
{
- if (_formatters.TryDequeue(out var data))
- data = new ArrayFormatter(128, SymbolTable.InvariantUtf8);
+ var data = _formatters.Rent();
try
{
var guid = Guid.NewGuid();
@@ -241,7 +240,8 @@ namespace Discord.API
}
finally
{
- _formatters.Enqueue(data);
+ data.Clear();
+ _formatters.Return(data);
}
}
diff --git a/src/Discord.Net.Serialization/Utils/Pool.cs b/src/Discord.Net.Serialization/Utils/Pool.cs
new file mode 100644
index 000000000..7b77e93fa
--- /dev/null
+++ b/src/Discord.Net.Serialization/Utils/Pool.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Diagnostics;
+using System.Threading;
+
+namespace Discord.Serialization
+{
+ //TODO: Replace pools in audio with this
+ public sealed class Pool
+ where T : class
+ {
+ private const int DefaultMaxElementsPerBucket = 50;
+
+ private readonly T[] _buffer;
+ private readonly Func _createFunc;
+
+ private SpinLock _lock;
+ private int _index;
+
+ public Pool(Func createFunc)
+ : this(createFunc, DefaultMaxElementsPerBucket) { }
+ public Pool(Func createFunc, int maxElementsPerBucket)
+ {
+ _createFunc = createFunc;
+ _lock = new SpinLock(Debugger.IsAttached);
+ _buffer = new T[maxElementsPerBucket];
+ }
+
+ public T Rent()
+ {
+ T result = null;
+ bool lockTaken = false;
+ try
+ {
+ _lock.Enter(ref lockTaken);
+
+ if (_index < _buffer.Length)
+ {
+ result = _buffer[_index];
+ _buffer[_index++] = null;
+ }
+ }
+ finally
+ {
+ if (lockTaken)
+ _lock.Exit(false);
+ }
+
+ if (result == null)
+ result = _createFunc();
+
+ return result;
+ }
+
+ public void Return(T obj)
+ {
+ bool lockTaken = false;
+ try
+ {
+ _lock.Enter(ref lockTaken);
+
+ if (_index != 0)
+ _buffer[--_index] = obj;
+ }
+ finally
+ {
+ if (lockTaken)
+ _lock.Exit(false);
+ }
+ }
+ }
+}
diff --git a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs
index 473b520c6..2f7474c7a 100644
--- a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs
+++ b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs
@@ -174,8 +174,7 @@ namespace Discord.API
{
CheckState();
- if (!_formatters.TryDequeue(out var data))
- data = new ArrayFormatter(128, SymbolTable.InvariantUtf8);
+ var data = _formatters.Rent();
try
{
var frame = new GatewaySocketFrame { Operation = opCode, Payload = payload };
@@ -185,7 +184,7 @@ namespace Discord.API
finally
{
data.Clear();
- _formatters.Enqueue(data);
+ _formatters.Return(data);
}
}
diff --git a/src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs b/src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs
index 0c3fdc188..12edbfea9 100644
--- a/src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs
+++ b/src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs
@@ -41,7 +41,7 @@ namespace Discord.Audio
private readonly Serializer _serializer;
private readonly SemaphoreSlim _connectionLock;
private readonly MemoryStream _decompressionStream;
- protected readonly ConcurrentQueue _formatters;
+ protected readonly Pool _formatters;
private CancellationTokenSource _connectCancelToken;
private IUdpSocket _udp;
@@ -61,7 +61,7 @@ namespace Discord.Audio
_udp = udpSocketProvider();
_udp.ReceivedDatagram += (data, index, count) => _receivedPacketEvent.InvokeAsync(data, index, count);
_serializer = serializer;
- _formatters = new ConcurrentQueue();
+ _formatters = new Pool(() => new ArrayFormatter(128, SymbolTable.InvariantUtf8));
_decompressionStream = new MemoryStream(10 * 1024); //10 KB
@@ -114,8 +114,7 @@ namespace Discord.Audio
public async Task SendAsync(VoiceOpCode opCode, object payload, RequestOptions options = null)
{
- if (!_formatters.TryDequeue(out var data))
- data = new ArrayFormatter(128, SymbolTable.InvariantUtf8);
+ var data = _formatters.Rent();
try
{
var frame = new VoiceSocketFrame { Operation = opCode, Payload = payload };
@@ -125,7 +124,7 @@ namespace Discord.Audio
finally
{
data.Clear();
- _formatters.Enqueue(data);
+ _formatters.Return(data);
}
}
public async Task SendAsync(byte[] data, int offset, int bytes)