Significant delay in sending large arrays (2.3.1 vs 2.4.0+)
Closed this issue · 4 comments
Large arrays that take seconds to send in 2.3.1 take 10+ minutes in 2.4.0+.
I have 2 servers, 1 acts as a master handling user data and the other as a game server.
The game server connects to the master and is sent a large chunk of data upon startup; this process takes 2-3 seconds in 2.3.1 and 10+ minutes in 2.4.0+ occasionally resulting in a crash or failure to send.
For Issues
- 2 standalone servers connected via DarkriftClient.dll, both hosted on different machines.
- Send a large array to the client and wait, my example uses an array containing 100k items.
This also happens server to client, even if on the same machine.
I wrote a quick server script and used the chat demo alongside it, the results locally were:
2.10.1: 2 minutes
2.3.1: 0.35 seconds
using DarkRift;
using DarkRift.Server;
using System;
using System.Collections.Generic;
namespace DarkriftIssue
{
public class Class1 : Plugin
{
public override bool ThreadSafe => true;
public override Version Version => new Version(0, 0, 0);
private List<string> words = new List<string>();
public Class1(PluginLoadData pluginLoadData) : base(pluginLoadData)
{
ClientManager.ClientConnected += ClientConnected;
}
protected override void Loaded(LoadedEventArgs args)
{
base.Loaded(args);
for(int i = 0; i < 100000; i++)
{
words.Add(i.ToString());
}
}
void ClientConnected(object sender, ClientConnectedEventArgs e)
{
e.Client.MessageReceived += Client_PlayerEvent;
}
public void Client_PlayerEvent(object sender, DarkRift.Server.MessageReceivedEventArgs e)
{
using (DarkRiftWriter writer = DarkRiftWriter.Create())
{
WriteEvent($"Preparing to send {words.Count} words at {DateTime.Now}", LogType.Info);
writer.Write(words.ToArray());
using (Message message = Message.Create(0, writer))
{
e.Client.SendMessage(message, SendMode.Reliable);
}
WriteEvent($"Sent at {DateTime.Now}", LogType.Info);
}
}
}
}
Hi,
I have one solution (tested)
In DarkRiftWriter.cs change function
public void Write(string[] value)
to
public void Write(string[] value)
{
buffer.EnsureLength(Position + 4); //Encodings suck, just do this manually
EndianHelper.WriteBytes(buffer.Buffer, Position, value.Length);
Position += 4;
buffer.Count = Math.Max(Length, Position);
int length = 0;
foreach(string b in value)
length += Encoding.GetByteCount(b);
buffer.EnsureLength(Position + (value.Length * 4) + length);
foreach (string b in value)
{
int bLen = Encoding.GetByteCount(b);
EndianHelper.WriteBytes(buffer.Buffer, Position, bLen);
Encoding.GetBytes(b, 0, b.Length, buffer.Buffer, Position + 4);
Position += 4 + bLen;
}
buffer.Count = Math.Max(Length, Position);
}
Tested resullt: 4ms
Just to confirm what I think you've done in this code: You've moved the EnsureLength call out so that it's not called once per string (ignore the array length bit) but only once per the whole array. I can see that sorting the performance problem to be honest.
I think when I first saw this I assumed it was a problem with the sending code rather than the allocation code. A simple test to see if that is actually the case would be to pass in an appropriatly large initial length when calling DarkRiftWriter.Create((int length)
since if it doesn't have to rearrange arrays constantly it should be back at 2.3.1 levels of performance. (Side note, you should really be doing this anyway rather than forcing DR to resize you arrays)
Good find!