As I experimented with checking the limits of a parallel system, I myself ran into this problem. Comment oleksii is a spot on (1k threads ~ = 1GB of memory). It is important to note that virtual memory space is reserved in this memory, and not the number of actually used memory. Memory exceptions occur when the system cannot transfer a continuous fragment of the virtual address space large enough to satisfy your request (insert rhetoric of memory fragmentation here). If you look at the process in the Windows task manager about the time of his death, you can see only 80-120 mb of "used" memory. To find out how much virtual address space is reserved, display the "Memory - Commit Size" column in the task manager.
To keep this short, I was able to break through the ~ 1k stream limit by switching the build configuration from x86 to 64 bits. This increases the amount of virtual address space available from (approximately) 2 GB to 6 TB + (depending on OS version), and my OutOfMemoryException is gone.
Here is a simple program that I created that illustrates this artifact, be sure to run it as x86 and see how it dies somewhere between the 1k and 1,5k threads, and then switch to 64-bit and it should work until it finishes without failures.
using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Threading; namespace TaskToy { class Program { static void Main( string[] args ) { List<Task> lTasks = new List<Task>(); int lWidth = 0; for ( int i = 0; i < 5000; i ++ ) { lTasks.Add( new Task( (o) => { Console.WriteLine( "B " + Interlocked.Increment( ref lWidth ) + " tid " + Thread.CurrentThread.ManagedThreadId ); Thread.Sleep( 60000 ); Console.WriteLine( "E " + Interlocked.Decrement( ref lWidth ) + " tid " + Thread.CurrentThread.ManagedThreadId ); }, null, TaskCreationOptions.LongRunning ) ); } Parallel.For( 0, lTasks.Count, ( i ) => { lTasks[i].Start(); } ); Task.WaitAll( lTasks.ToArray() ); Console.WriteLine( "DONE - press any key..." ); Console.ReadKey( true ); } } }
PS The variable 'lWidth' indicates the current level of concurrency, that is, how many tasks are actually being performed at the same time.
In general, it was a fun academic experiment, but it will probably be βseveralβ years before launching thousands of threads, which will bring a profitable income. It is probably advisable to limit the number of threads that you switch to something more practical - probably an order of magnitude less than "thousands".
source share