private void DetectCompletion(ProducerConsumerBuffer buffer, CancellationToken token) { while ((this.producers.Any(x => x.ProducerState != State.Completed) || (this.producerCount > this.consumerCount + this.discardConsumerCount && this.consumers.Any(x => x.ConsumerState != State.Completed))) && !token.IsCancellationRequested) { Thread.Sleep(1); } if (token.IsCancellationRequested) { this.logger?.LogInformation($"{this.LogName}: Completed execution by stop!"); } else { foreach (var consumer in this.consumers) { consumer.ConsumerState = State.Completed; consumer.Finish(); } this.logger?.LogInformation($"{this.LogName}: Completed execution as all producers and consumers has finished their job!"); } this.OnCompleted?.Invoke(this, EventArgs.Empty); }
private void LogPerformance(ProducerConsumerBuffer buffer, CancellationToken token) { int sleep = this.Configuration.LogPerfomanceMs; double ratio = 1000.0 / sleep; long lastProducer, lastDiscardProducer, lastConsumer, lastDiscardConsumer, perProducer, perProducerDiscard, perConsumer, perConsumerDiscard; while ((this.producers.Any(x => x.ProducerState != State.Completed) || (this.producerCount > this.consumerCount + this.discardConsumerCount && this.consumers.Any(x => x.ConsumerState != State.Completed))) && !token.IsCancellationRequested) { lastProducer = this.producerCount; lastConsumer = this.consumerCount; lastDiscardProducer = this.discardProducerCount; lastDiscardConsumer = this.discardConsumerCount; Thread.Sleep(sleep); perProducer = (long)(ratio * (this.producerCount - lastProducer)); perConsumer = (long)(ratio * (this.consumerCount - lastConsumer)); perProducerDiscard = (long)(ratio * (this.discardProducerCount - lastDiscardProducer)); perConsumerDiscard = (long)(ratio * (this.discardConsumerCount - lastDiscardConsumer)); this.logger.LogInformation($"{this.LogName}: Produce/s: {perProducer} Discard/s: {perProducerDiscard} Consume/s: {perConsumer} Discard/s: {perConsumerDiscard} Buffer: {buffer.Count}"); } }
private void StartDetectCompletion(ProducerConsumerBuffer buffer, CancellationToken token) { new Thread(() => this.DetectCompletion(buffer, token)) { IsBackground = true, Priority = ThreadPriority.AboveNormal, }.Start(); }
private void StartLogPerformance(ProducerConsumerBuffer buffer, CancellationToken token) { if (this.logger != null && this.Configuration.LogPerfomance) { new Thread(() => this.LogPerformance(buffer, token)) { IsBackground = true, Priority = ThreadPriority.Lowest, }.Start(); } }
private async Task StartProducer(IProducer producer, ProducerConsumerBuffer buffer, CancellationToken token) { while (!token.IsCancellationRequested && producer.ProducerState != State.Completed) { if (await producer.Produce(token) is object item) { buffer.AddItem(item, token); Interlocked.Increment(ref this.producerCount); } else { Interlocked.Increment(ref this.discardProducerCount); } } }
private async Task StartConsumer(IConsumer consumer, ProducerConsumerBuffer buffer, CancellationToken token) { while (!token.IsCancellationRequested && consumer.ConsumerState != State.Completed) { var item = await buffer.GetItem(token); if (consumer.CanConsume(item)) { consumer.Consume(item, token); Interlocked.Increment(ref this.consumerCount); } else { Interlocked.Increment(ref this.discardConsumerCount); } } }
private void Schedule(CancellationToken token) { this.logger?.LogInformation($"{this.LogName}: Starting producers and consumers!"); var buffer = new ProducerConsumerBuffer(); this.StartDetectCompletion(buffer, token); this.StartLogPerformance(buffer, token); this.consumers .AsParallel() .Select(x => this.StartConsumer(x, buffer, token).ConfigureAwait(false)) .ToList(); this.producers .AsParallel() .Select(x => this.StartProducer(x, buffer, token).ConfigureAwait(false)) .ToList(); }