예제 #1
0
        public void AddWorkItem_ItemsProcessed(int totItems, int totThreads, int maxQueuedItems)
        {
            MockWorker mw = new MockWorker();
            CancellationTokenSource ts       = new CancellationTokenSource();
            List <MockWorkOut>      doneWork = new List <MockWorkOut>();
            var cfg = GetConfig(totThreads, maxQueuedItems);

            using (FIFOWorker <MockWorkIn, MockWorkOut> fifo = new FIFOWorker <MockWorkIn, MockWorkOut>(cfg, mw.DoMockWork_Simple))
            {
                foreach (int inputIx in Enumerable.Range(1, totItems))
                {
                    foreach (var outItem in fifo.AddWorkItem(new MockWorkIn(inputIx), ts.Token))
                    {
                        doneWork.Add(outItem);
                    }
                }
                foreach (var outItem in fifo.Flush(ts.Token))
                {
                    doneWork.Add(outItem);
                }
            }

            Assert.AreEqual(Enumerable.Range(1, totItems), doneWork.Select(f => f.originalInputItem.ix));
            Assert.AreEqual(Enumerable.Range(1, totItems), mw.doneWork.Where(f => !f.Item1).OrderBy(f => f.Item2.ix).Select(f => f.Item2.ix));
        }
예제 #2
0
        public void AddWorkItem_OneItemProcessed()
        {
            MockWorker mw = new MockWorker();
            CancellationTokenSource ts       = new CancellationTokenSource();
            List <MockWorkOut>      doneWork = new List <MockWorkOut>();
            int inputIx        = 1;
            int totThreads     = 1;
            int maxQueuedItems = 1;
            var cfg            = GetConfig(totThreads, maxQueuedItems);

            using (FIFOWorker <MockWorkIn, MockWorkOut> fifo = new FIFOWorker <MockWorkIn, MockWorkOut>(cfg, mw.DoMockWork_Simple))
            {
                foreach (var outItem in fifo.AddWorkItem(new MockWorkIn(inputIx), ts.Token).Concat(fifo.Flush(ts.Token)))
                {
                    doneWork.Add(outItem);
                }
            }

            Assert.AreEqual(1, doneWork.Count);
            Assert.AreEqual(inputIx, doneWork.First().originalInputItem.ix);
            Assert.AreEqual(1, mw.doneWork.Count);
            Assert.AreEqual(false, mw.doneWork.First().Item1);
            Assert.AreEqual(inputIx, mw.doneWork.First().Item2.ix);
            Assert.AreEqual(inputIx, mw.doneWork.First().Item3.originalInputItem.ix);
        }
예제 #3
0
        public void AddWorkItem_Cancels(int totThreads)
        {
            MockWorker mw = new MockWorker();
            CancellationTokenSource ts       = new CancellationTokenSource();
            List <MockWorkOut>      doneWork = new List <MockWorkOut>();
            var cfg = new FIFOWorkerConfig(totThreads);
            FIFOWorker <MockWorkIn, MockWorkOut> fifo = new FIFOWorker <MockWorkIn, MockWorkOut>(cfg, mw.DoMockWorkBlocking);
            int countTask = fifo.AddWorkItem(new MockWorkIn(1), ts.Token).Count();

            mw.TriggerOnBlockedWork(() => ts.Cancel());

            Assert.Throws <TaskCanceledException>(() =>
            {
                try
                {
                    fifo.Dispose();
                }
                catch (AggregateException ag)
                {
                    throw ag.GetBaseException();
                }
            });
            Assert.AreEqual(1, mw.doneWork.Count(f => f.Item1));
            Assert.AreEqual(1, mw.doneWork.Count());
        }
예제 #4
0
        public void Dispose_ExceptionInWorkerPropagates(int totThreads)
        {
            TaskCompletionSource <object> taskBlocker1 = new TaskCompletionSource <object>();

            MockWorkOut DoMockWorkBlocking(MockWorkIn work, CancellationToken token)
            {
                taskBlocker1.Task.Wait();
                throw new MockException();
            }

            CancellationTokenSource ts       = new CancellationTokenSource();
            List <MockWorkOut>      doneWork = new List <MockWorkOut>();
            var cfg = new FIFOWorkerConfig(totThreads);
            FIFOWorker <MockWorkIn, MockWorkOut> fifo = new FIFOWorker <MockWorkIn, MockWorkOut>(cfg, DoMockWorkBlocking);
            int count = fifo.AddWorkItem(new MockWorkIn(1), ts.Token).Count();

            Assert.Throws <MockException>(() =>
            {
                try
                {
                    taskBlocker1.SetResult(null);
                    fifo.Dispose();
                }
                catch (AggregateException ag)
                {
                    throw ag.GetBaseException();
                }
            });
        }
예제 #5
0
        public void Dispose_CancelsPendingTasks(int totThreads)
        {
            TaskCompletionSource <object> taskBlocker1 = new TaskCompletionSource <object>();
            TaskCompletionSource <object> taskBlocker2 = new TaskCompletionSource <object>();
            bool completed = false;

            int totBlockCalled = 0;

            MockWorkOut DoMockWorkBlocking(MockWorkIn work, CancellationToken token)
            {
                Interlocked.Increment(ref totBlockCalled);
                taskBlocker2.SetResult(null);
                taskBlocker1.Task.Wait();
                Task.Delay(1, token).Wait();
                completed = true;
                return(new MockWorkOut(work));
            }

            CancellationTokenSource ts       = new CancellationTokenSource();
            List <MockWorkOut>      doneWork = new List <MockWorkOut>();
            var cfg = new FIFOWorkerConfig(totThreads);
            FIFOWorker <MockWorkIn, MockWorkOut> fifo = new FIFOWorker <MockWorkIn, MockWorkOut>(cfg, DoMockWorkBlocking);
            int count = fifo.AddWorkItem(new MockWorkIn(1), ts.Token).Count();

            taskBlocker2.Task.Wait();
            taskBlocker1.SetResult(null);


            Assert.AreEqual(1, totBlockCalled);
            Assert.AreEqual(0, count);
            Assert.DoesNotThrow(fifo.Dispose);
            Assert.AreEqual(true, completed);
        }
예제 #6
0
 public CollectionDeserializerAsync(FIFOWorkerConfig fifowConfig, TypeModel typeModel, int desiredBatchSize_bytes = 1024 * 64)
 {
     this.desiredBatchSize_bytes = desiredBatchSize_bytes;
     fifow          = new FIFOWorker <BatchIn, BatchOut>(fifowConfig, HandleWorkerOutput);
     this.typeModel = typeModel;
     t_ParallelServices_ArrayWrapper = typeof(ParallelServices_ArrayWrapper <T>);
     typeModel.SetupParallelServices <T>();
     objPoolBufferWriterSerializedBatch = new DefaultObjectPool <ArrayPoolBufferWriter <byte> >(
         new ArrayPoolBufferWriterObjectPoolPolicy <byte>(Math.Max(1024 * 64, desiredBatchSize_bytes)),
         fifowConfig.MaxQueuedItems);
     objPoolList = new DefaultObjectPool <List <int> >(new ListObjectPoolPolicy <int>(64), fifowConfig.MaxQueuedItems);
 }
예제 #7
0
 protected virtual void Dispose(bool disposing)
 {
     if (disposing)
     {
         fifow.Dispose();
     }
     fifow = null;
     objPoolBufferWriterSerializedBatch = null;
     objPoolList = null;
     typeModel   = null;
     t_ParallelServices_ArrayWrapper = null;
 }
예제 #8
0
 protected virtual void Dispose(bool disposing)
 {
     if (disposing)
     {
         fifow?.Dispose();
     }
     fifow  = null;
     r_opts = null;
     objPoolBufferWriterBodies      = null;
     objPoolBufferWriterBodyLengths = null;
     arrPoolOutputBatch             = null;
 }
예제 #9
0
 public CollectionDeserializerAsync(FIFOWorkerConfig fifowConfig, MessagePackSerializerOptions r_opts, int desiredBatchSize_bytes = 1024 * 64)
 {
     fifow = new FIFOWorker <BatchWithBufferWriters, BatchWithFramesArray>(fifowConfig, HandleWorkerOutput);
     this.desiredBatchSize_bytes = desiredBatchSize_bytes;
     objPoolBufferWriterBodies   = new DefaultObjectPool <ArrayPoolBufferWriter <byte> >(
         new ArrayPoolBufferWriterObjectPoolPolicy <byte>(Math.Max(1024 * 64, desiredBatchSize_bytes)),
         fifowConfig.MaxQueuedItems);
     objPoolBufferWriterBodyLengths = new DefaultObjectPool <ArrayPoolBufferWriter <int> >(
         new ArrayPoolBufferWriterObjectPoolPolicy <int>(1024),
         fifowConfig.MaxQueuedItems);
     arrPoolOutputBatch = ArrayPool <Frame <T> > .Shared;
     this.r_opts        = r_opts;
 }
예제 #10
0
 public CollectionSerializerAsync(Stream stream, FIFOWorkerConfig fifowConfig, BatchSizeEstimatorConfig estimatorConfig, TypeModel typeModel)
 {
     this.stream    = stream;
     fifow          = new FIFOWorker <List <T>, MemoryStream>(fifowConfig, HandleWorkerOutput);
     this.typeModel = typeModel;
     typeModel.SetupParallelServices <T>();
     batchEstimator      = new BatchSizeEstimator(estimatorConfig);
     objPoolList         = new DefaultObjectPool <List <T> >(new ListObjectPoolPolicy <T>(64), fifowConfig.MaxQueuedItems);
     objPoolMemoryStream = new DefaultObjectPool <MemoryStream>(
         new MemoryStreamObjectPoolPolicy(Math.Max(1024 * 64, estimatorConfig.DesiredBatchSize_bytes)),
         fifowConfig.MaxQueuedItems);
     desiredBatchSize = 1;
     currentBatch     = objPoolList.Get();
 }
예제 #11
0
 protected virtual void Dispose(bool disposing)
 {
     if (disposing)
     {
         FlushAsync().Wait();
         fifow.Dispose();
     }
     fifow               = null;
     batchEstimator      = null;
     objPoolList         = null;
     objPoolMemoryStream = null;
     currentBatch        = null;
     typeModel           = null;
 }
 public CollectionSerializerAsync(Stream stream, FIFOWorkerConfig fifowConfig, BatchSizeEstimatorConfig estimatorConfig, MessagePackSerializerOptions w_opts)
 {
     this.stream               = stream;
     fifow                     = new FIFOWorker <ArrayPoolBufferWriter <T>, BatchWithBufferWriters>(fifowConfig, HandleWorkerOutput);
     batchEstimator            = new BatchSizeEstimator(estimatorConfig);
     this.w_opts               = w_opts;
     objPoolBufferWriterBodies = new DefaultObjectPool <ArrayPoolBufferWriter <byte> >(
         new ArrayPoolBufferWriterObjectPoolPolicy <byte>(Math.Max(1024 * 64, estimatorConfig.DesiredBatchSize_bytes)),
         fifowConfig.MaxQueuedItems);
     objPoolBufferWriterBodyLengths = new DefaultObjectPool <ArrayPoolBufferWriter <int> >(
         new ArrayPoolBufferWriterObjectPoolPolicy <int>(1024),
         fifowConfig.MaxQueuedItems);
     objPoolOutputBatch = new DefaultObjectPool <ArrayPoolBufferWriter <T> >(
         new ArrayPoolBufferWriterObjectPoolPolicy <T>(1024),
         fifowConfig.MaxQueuedItems);
     currentBatch     = objPoolOutputBatch.Get();
     desiredBatchSize = 1;
     formatterT       = w_opts.Resolver.GetFormatterWithVerify <T>();
 }
예제 #13
0
        public void Dispose_ThrowsOnCancelledTasks(int totThreads)
        {
            TaskCompletionSource <object> taskBlocker1 = new TaskCompletionSource <object>();
            TaskCompletionSource <object> taskBlocker2 = new TaskCompletionSource <object>();
            bool completed = false;

            int totBlockCalled = 0;

            MockWorkOut DoMockWorkBlocking(MockWorkIn work, CancellationToken token)
            {
                Interlocked.Increment(ref totBlockCalled);
                taskBlocker2.SetResult(null);
                taskBlocker1.Task.Wait();
                Task.Delay(1, token).Wait();
                completed = true;
                return(new MockWorkOut(work));
            }

            CancellationTokenSource ts       = new CancellationTokenSource();
            List <MockWorkOut>      doneWork = new List <MockWorkOut>();
            var cfg = new FIFOWorkerConfig(totThreads);
            FIFOWorker <MockWorkIn, MockWorkOut> fifo = new FIFOWorker <MockWorkIn, MockWorkOut>(cfg, DoMockWorkBlocking);
            int count = fifo.AddWorkItem(new MockWorkIn(1), ts.Token).Count();

            taskBlocker2.Task.Wait();
            ts.Cancel();

            Assert.Throws <TaskCanceledException>(() =>
            {
                try
                {
                    taskBlocker1.SetResult(null);
                    fifo.Dispose();
                }
                catch (AggregateException ag)
                {
                    throw ag.GetBaseException();
                }
            });
            Assert.AreEqual(1, totBlockCalled);
            Assert.AreEqual(0, count);
            Assert.AreEqual(false, completed);
        }
 protected virtual void Dispose(bool disposing)
 {
     if (disposing)
     {
         FlushAsync().Wait();
         fifow?.Dispose();
         if (currentBatch != null)
         {
             objPoolOutputBatch?.Return(currentBatch);
         }
     }
     w_opts = null;
     objPoolBufferWriterBodies      = null;
     objPoolBufferWriterBodyLengths = null;
     objPoolOutputBatch             = null;
     fifow          = null;
     batchEstimator = null;
     currentBatch   = null;
     formatterT     = null;
 }
        public void Serialize(ref MessagePackWriter writer, TFrameList value, MessagePackSerializerOptions options)
        {
            if (value == null)
            {
                writer.WriteNil();
                return;
            }
            Interlocked.Increment(ref ParallelGatekeeperSingleton.wrapperDepth);
            try
            {
                FrameFormatterSerializationOptions frameOptions = options.GetOptionParams();

                if (frameOptions.FIFOWorkerConfig.MaxConcurrentTasks < 1 || ParallelGatekeeperSingleton.wrapperDepth != 1)
                {
                    SerializeSynchronous(ref writer, value, options);
                    return;
                }
                int count = value.Count;
                writer.WriteArrayHeader(count);
                BatchSizeEstimator        batchEstimator = new BatchSizeEstimator(frameOptions.BatchSizeEstimatorConfig);
                IMessagePackFormatter <T> formatterT     = options.Resolver.GetFormatterWithVerify <T>();
                bool isOldSpec = writer.OldSpec;

                BatchWithBufferWriters ProcessItems(ArraySegment <Frame <T> > batch, CancellationToken token)
                {
                    BatchWithBufferWriters batchOut = new BatchWithBufferWriters();

                    batchOut.concatenatedBodies = objPoolBufferWriterBodies.Get();
                    batchOut.lengths            = objPoolBufferWriterBodyLengths.Get();
                    MessagePackWriter writerBody = new MessagePackWriter(batchOut.concatenatedBodies)
                    {
                        OldSpec = isOldSpec, CancellationToken = token
                    };
                    var spanIn = batch.AsSpan();
                    int prevWrittenBytesCount = 0;
                    int sumLen = 0;

                    for (int ix = 0; ix < spanIn.Length; ix++)
                    {
                        formatterT.Serialize(ref writerBody, spanIn[ix], options);
                        writerBody.Flush();
                        int currWrittenBytesCount = batchOut.concatenatedBodies.WrittenCount;
                        int objLen = currWrittenBytesCount - prevWrittenBytesCount;
                        prevWrittenBytesCount          = currWrittenBytesCount;
                        batchOut.lengths.GetSpan(1)[0] = objLen;
                        batchOut.lengths.Advance(1);
                        sumLen += objLen;
                    }
                    if (spanIn.Length > 0)
                    {
                        batchEstimator.UpdateEstimate((float)sumLen / (float)spanIn.Length); // update with avg instead of updating for every loop item. It's not exact, but it's faster
                    }
                    return(batchOut);
                }

                ListFrameWrapper valueWrapper = GetTFrameListWrapper(value);

                Frame <T>[] valueArray = valueWrapper.AsFrameArray();
                using (var fifow = new FIFOWorker <ArraySegment <Frame <T> >, BatchWithBufferWriters>(frameOptions.FIFOWorkerConfig, ProcessItems))
                {
                    int i = 0;
                    while (i < count)
                    {
                        int batchSize = Math.Min(count - i, batchEstimator.RecomendedBatchSize);
                        if (batchSize <= 0)
                        {
                            throw new StreamSerializationException($"Invalid batch sequence length: {batchSize}");
                        }
                        ArraySegment <Frame <T> > sourceSegment = new ArraySegment <Frame <T> >(valueArray, i, batchSize);
                        foreach (BatchWithBufferWriters batchOutput in fifow.AddWorkItem(sourceSegment, writer.CancellationToken))
                        {
                            BatchToStream(ref writer, batchOutput);
                        }

                        i += batchSize;
                    }
                    foreach (BatchWithBufferWriters batchOutput in fifow.Flush(writer.CancellationToken))
                    {
                        BatchToStream(ref writer, batchOutput);
                    }
                }
            }
            finally
            {
                Interlocked.Decrement(ref ParallelGatekeeperSingleton.wrapperDepth);
            }
        }