Description
When starting Parallel.For with more long running tasks than CPU-cores, then suddenly background-timers no longer fires on .NET 6.0. Instead the Parallel.For continues to schedule new threads.
Configuration
When running this snippet on .NET 6.0, then background-Timer stops writing to console.
using System ;
using System . Threading ;
using System . Threading . Tasks ;
using Microsoft . Extensions . DependencyInjection ;
using Microsoft . Extensions . Hosting ;
using Microsoft . Extensions . Logging ;
using NLogWait ;
Console . Title = $ "LogDemo - { Environment . ProcessId } (PID)";
var builder = Host . CreateDefaultBuilder ( args ) ;
var host = builder
. ConfigureServices ( services =>
{
services . AddLogging ( builder => builder . AddConsole ( ) ) ;
services . AddHostedService < Worker > ( ) ;
} )
. Build ( ) ;
await host . RunAsync ( ) ;
namespace NLogWait
{
public sealed class Worker : BackgroundService
{
private readonly ILogger < Worker > _logger ;
public Worker ( ILogger < Worker > logger ) => _logger = logger ;
private readonly object SyncRoot = new object ( ) ;
private Timer Timer ;
private readonly System . Collections . Concurrent . ConcurrentQueue < int > Queue = new System . Collections . Concurrent . ConcurrentQueue < int > ( ) ;
protected override Task ExecuteAsync ( CancellationToken stoppingToken )
{
Timer = new Timer ( ( s ) => TimerExecute ( ) ) ;
_logger . LogInformation ( "Timer Started" ) ;
Timer . Change ( 0 , Timeout . Infinite ) ;
Parallel . For ( 0 ,
200 ,
new ParallelOptions ( ) , // { MaxDegreeOfParallelism = System.Environment.ProcessorCount * 2 },
_ =>
{
_logger . LogInformation ( "Worker Thead Created" ) ;
while ( ! stoppingToken . IsCancellationRequested )
{
while ( Queue . Count > 1000 )
{
lock ( SyncRoot )
{
if ( Queue . Count < 1000 )
break ;
Monitor . Wait ( SyncRoot ) ;
}
}
Queue . Enqueue ( System . Environment . CurrentManagedThreadId ) ;
}
} ) ;
return Task . CompletedTask ;
}
private void TimerExecute ( )
{
do
{
_logger . LogInformation ( "Timer Working" ) ;
lock ( SyncRoot )
{
for ( int i = 0 ; i < 1000 ; ++ i )
{
if ( ! Queue . TryDequeue ( out var _ ) )
break ;
}
Monitor . PulseAll ( SyncRoot ) ;
}
} while ( Queue . Count > 1000 ) ;
_logger . LogInformation ( "Timer Scheduled" ) ;
Timer . Change ( 1 , Timeout . Infinite ) ;
}
}
}
Regression?
When running on .NET 5.0, then background-timer still get time-slots.
Analysis
The issue disappear when using:
new ParallelOptions ( ) { MaxDegreeOfParallelism = System . Environment . ProcessorCount * 2 } , Reactions are currently unavailable
Description
When starting
Parallel.Forwith more long running tasks than CPU-cores, then suddenly background-timers no longer fires on .NET 6.0. Instead the Parallel.For continues to schedule new threads.Configuration
When running this snippet on .NET 6.0, then background-Timer stops writing to console.
Regression?
When running on .NET 5.0, then background-timer still get time-slots.
Analysis
The issue disappear when using: