Stream short [] ~ 800 times slower than stream byte [] - How to speed it up?

I am moving several large arrays short[]between processes using WCF in streaming mode, and I ran into a problem when the transfer is very slow.

I did some tests, and it turned out that passing an array is short[]about 800 times slower than using an array byte[]that contains the same number of bytes.

I assume that I should be doing something wrong here, as this behavior cannot be expected.

Given the playback below, can anyone suggest how I can speed it up?

Please note that I use streaming mode because the arrays are VERY large, and using non-streaming mode seems to use three times the size of the array during transmission. (I am wrapping a 32-bit third-party managed DLL in a separate process so that it can be called from a 64-bit C # program through WCF.)

Here is the server and client code. It seems pretty long, but it's the shortest full review I can come up with ...

The code is very simple: the WCF interface has only two methods: one accepts a parameter short[], and the other accepts a parameter byte[]. I test it by passing short[]and byte[], each of which contains the same number of bytes, and use Stopwatchfor time how long it takes.

, ITest , - .

- , ENTER .

, .Net 4.6.2, .

using System;
using System.Diagnostics;
using System.ServiceModel;
using Shared;

namespace Shared
{
    [ServiceContract]
    interface ITest
    {
        [OperationContract]
        void ShortTest(short[] array);

        [OperationContract]
        void ByteTest(byte[] array);
    }
}

namespace Client
{
    class Client
    {
        static void Main()
        {
            int arraySizeInBytes = 10 * 1024 * 1024;

            var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
            {
                MaxReceivedMessageSize = 4*arraySizeInBytes + 1024,
                SendTimeout            = TimeSpan.FromHours(1), // To allow debugging without timeouts.
                ReceiveTimeout         = TimeSpan.FromHours(1),
                ReaderQuotas           = {MaxArrayLength = 4*arraySizeInBytes + 1024},
                TransferMode           = TransferMode.Streamed
            };

            var channelFactory = new ChannelFactory<ITest>(binding, "net.pipe://localhost/wcftest");
            var proxy = channelFactory.CreateChannel();

            short[] shorts = new short[arraySizeInBytes/sizeof(short)];

            for (int i = 0; i < shorts.Length; ++i) // Touch entire array to ensure memory allocated.
                shorts[i] = 1;

            byte[] bytes = new byte[arraySizeInBytes];

            for (int i = 0; i < bytes.Length; ++i) // Touch entire array to ensure memory allocated.
                bytes[i] = 1;

            Stopwatch sw = new Stopwatch();

            while (true)
            {
                Console.WriteLine("Press <ENTER> to call ByteTest() and ShortTest()");
                Console.ReadLine();

                Console.WriteLine("Calling ByteTest()");
                sw.Restart();
                proxy.ByteTest(bytes);
                Console.WriteLine("ByteTest() took " + sw.Elapsed);

                Console.WriteLine("Calling ShortTest()");
                sw.Restart();
                proxy.ShortTest(shorts);
                Console.WriteLine("ShortTest() took " + sw.Elapsed);
            }
        }
    }
}

SERVER

using System;
using System.ServiceModel;
using System.Threading;
using Shared;

namespace Shared
{
    [ServiceContract]
    interface ITest
    {
        [OperationContract]
        void ShortTest(short[] array);

        [OperationContract]
        void ByteTest(byte[] array);
    }
}

namespace Server
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    class Server : ITest
    {
        static void Main()
        {
            int arraySizeInBytes = 10 * 1024 * 1024;

            var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
            {
                MaxReceivedMessageSize = 4*arraySizeInBytes + 1024,
                SendTimeout            = TimeSpan.FromHours(1),  // To allow debugging without timeouts.
                ReceiveTimeout         = TimeSpan.FromHours(1),
                ReaderQuotas           = {MaxArrayLength = 4*arraySizeInBytes + 1024 },
                TransferMode           = TransferMode.Streamed
            };

            var serviceHost = new ServiceHost(new Server());
            serviceHost.AddServiceEndpoint(typeof(ITest), binding, "net.pipe://localhost/wcftest");
            serviceHost.Open();

            Console.WriteLine("Server started. Close console to stop.");
            Thread.Sleep(TimeSpan.FromHours(10));
        }

        public void ShortTest(short[] array)
        {
            Console.WriteLine("ShortTest() received array of size " + array.Length);
        }

        public void ByteTest(byte[] array)
        {
            Console.WriteLine("ByteTest() received array of size " + array.Length);
        }
    }
}

, , :

Press <ENTER> to call ByteTest() and ShortTest()

Calling ByteTest()
ByteTest() took 00:00:00.0519079
Calling ShortTest()
ShortTest() took 00:00:41.9868413
Press <ENTER> to call ByteTest() and ShortTest()

Calling ByteTest()
ByteTest() took 00:00:00.0344547
Calling ShortTest()
ShortTest() took 00:00:41.4307394
Press <ENTER> to call ByteTest() and ShortTest()

- , short[]?

, byte[], .

+4

Source: https://habr.com/ru/post/1653007/


All Articles