C
C#ā€¢2y ago
infernus8349

āœ… ThreadPooling

How to release the ram used by the Thread pooling after the execution. It created like 42 threads at the starting of the program and then it reduced to 21 while execution is still moving on and when its done, the number of threads change to 10. But the problem is that the ram used by this process is at 1.4GB ram but those are not getting reduced as the threads in Thread pool reduces. How to release this memory?
94 Replies
mtreit
mtreitā€¢2y ago
This has nothing to do with thread pooling. It's just the way garbage collection works. I really wouldn't worry about it personally.
infernus8349
infernus8349OPā€¢2y ago
GC.Collect(); at the end and still its at 1.4 GB
mtreit
mtreitā€¢2y ago
In that case you might have objects that are still rooted and ineligible for GC. Depending on your knowledge you can take a memory dump and use a debugger like windbg to figure out what's going on.
infernus8349
infernus8349OPā€¢2y ago
windbg???? is that opensource?
mtreit
mtreitā€¢2y ago
It's not open source (as far as I know) but it's freely available https://apps.microsoft.com/store/detail/windbg-preview/9PGJGD53TN86?hl=en-us&gl=us
Get WinDbg Preview from the Microsoft Store
We've updated WinDbg to have more modern visuals, faster windows, a full-fledged scripting experience, and Time Travel Debugging, all with the easily extensible debugger data model front and center. WinDbg Preview is using the same underlying engine as WinDbg today, so all the commands, extensions, and workflows you're used to will still work as...
infernus8349
infernus8349OPā€¢2y ago
i se thanks for letting me know i will check it out for usre
mtreit
mtreitā€¢2y ago
You can use !dumpheap -stat to see what objects are still on the heap and !gcroot to see where objects are still rooted. It's a fairly low level tool so might be a bit of a learning curve
infernus8349
infernus8349OPā€¢2y ago
I have another question, for like i have a lot of functions that is going to run really fast, so is it a good idea to use threadpooling or just use async. NOTE : performance is important i see, thanks for that information and the code to run
mtreit
mtreitā€¢2y ago
async makes your code slower not faster. I just gave a talk on this topic actually... https://youtu.be/8lUs9ukVrFY
C# Community Discord
YouTube
Solution1: Threads, Tasks and more with Mike Treit
This presentation recaps some of the basics of writing code that makes use of threads, tasks and asynchronous features in C#. It is a modified version of a talk the author has given to his team at Microsoft. This is an intermediate level talk aimed at developers still learning how to write parallel and async code in C#.
infernus8349
infernus8349OPā€¢2y ago
i see, so how can i run a async function in threadpooling? i mean like lets just say i have 100 threads in threadpool and lets just say its the max and lets assume that all the threads are running at the moment if i want to add another process on it to run, how can i do that (i know it queues but i prefer if one of the thread can just run the current one the the new one simultaneously) is that possible?
mtreit
mtreitā€¢2y ago
That's a state called thread pool exhaustion and it's really bad...but cpu-bound work should typically be fast enough that it's not a problem. It's doing I/O that is slow enough to be a problem. You can use TaskCreationOptions.LongRunning to bypass the thread pool...but that's also slower. (The talk covers all of this) The answer will really depend on your exact workload characteristics. The demo at the end of the talk shows some details you will probably find useful.
infernus8349
infernus8349OPā€¢2y ago
Surely i will listen to that. The reason why i asked this is because most of the run takes like 2 seconds as there are multiple callings to the database and a lot of code execution and each time this whole process has to be done is when a custom does something. so basically the thread gets busy with one single operation of the custom which means the number of threads would increase at an alarming rate which is quite bad. This is why i asked if i could just run one of the thread if busy as async rather than queueing it *customer
mtreit
mtreitā€¢2y ago
If you are making a database call over the network that is I/O and you should definitely be using async / await.
infernus8349
infernus8349OPā€¢2y ago
database is local for more performance
mtreit
mtreitā€¢2y ago
If it's not purely in-memory (has to go to disk) you should still use async But async already uses the thread pool, it should be transparent to your code
infernus8349
infernus8349OPā€¢2y ago
yes it has to go to disk (not everytime as it depends on the database) if async uses threadpooling, then as per what you have mentioned, how can async be slower than threadpooling
mtreit
mtreitā€¢2y ago
If it's taking a second I question what is going on...that's extremely slow async had its own overhead Due to how the async state machine works
infernus8349
infernus8349OPā€¢2y ago
mostly i get data from another service over the internet which is the actual thing that is taking time the rest would be done in like 200 milliseconds or less the service thing, that may take time and it depends isee
mtreit
mtreitā€¢2y ago
async frees the thread pool thread, avoiding the thread pool exhaustion scenario
infernus8349
infernus8349OPā€¢2y ago
aah, so you are saying that in my case, async is more than enough?
mtreit
mtreitā€¢2y ago
But only use it for things that do I/O
infernus8349
infernus8349OPā€¢2y ago
i see
mtreit
mtreitā€¢2y ago
Yes it should be
infernus8349
infernus8349OPā€¢2y ago
so for other processes, i should be using actual threadpooling rather than async?
mtreit
mtreitā€¢2y ago
You should just use Tasks
infernus8349
infernus8349OPā€¢2y ago
i see
mtreit
mtreitā€¢2y ago
Which use the thread pool by default Watch the talk it covers all of this in some detail šŸ™‚ If you have followup questions feel free to ping me
infernus8349
infernus8349OPā€¢2y ago
I will see the whole thing btw this is the code i ran which hits at 1.4GB of ram usage
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using System;

namespace ConsoleApp
{
class Program
{
public int QueueLength;
public Program()
{
QueueLength = 0;
}

public void Produce(random_class ware)
{

ThreadPool.QueueUserWorkItem(new WaitCallback(Consume), ware);
QueueLength++;
}

public void Consume(Object obj)
{
Console.WriteLine("Thread " + Thread.CurrentThread.GetHashCode() + " consumes " + ((random_class)obj).id);

QueueLength--;
}

public static void Main(String[] args)
{
Thread.Sleep(2000);
Program obj = new Program();
for (int i = 0; i < 10000000; i++)
{
obj.Produce(new random_class(i));
}
Console.WriteLine("Thread " + Thread.CurrentThread.GetHashCode());
while (obj.QueueLength != 0)
{
Thread.Sleep(1000);
}

Console.Read();
}
}

public class random_class
{
public int id;
public random_class(int _id)
{
id = _id;
}
}
}
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using System;

namespace ConsoleApp
{
class Program
{
public int QueueLength;
public Program()
{
QueueLength = 0;
}

public void Produce(random_class ware)
{

ThreadPool.QueueUserWorkItem(new WaitCallback(Consume), ware);
QueueLength++;
}

public void Consume(Object obj)
{
Console.WriteLine("Thread " + Thread.CurrentThread.GetHashCode() + " consumes " + ((random_class)obj).id);

QueueLength--;
}

public static void Main(String[] args)
{
Thread.Sleep(2000);
Program obj = new Program();
for (int i = 0; i < 10000000; i++)
{
obj.Produce(new random_class(i));
}
Console.WriteLine("Thread " + Thread.CurrentThread.GetHashCode());
while (obj.QueueLength != 0)
{
Thread.Sleep(1000);
}

Console.Read();
}
}

public class random_class
{
public int id;
public random_class(int _id)
{
id = _id;
}
}
}
mtreit
mtreitā€¢2y ago
QueueUserWorkItem šŸ‘€
infernus8349
infernus8349OPā€¢2y ago
waht happeend? 0_0 i found this code online and i just changed the looping times to 10 million
mtreit
mtreitā€¢2y ago
That's like a very old mechanism you shouldn't really use in modern code. You should just use Tasks instead
infernus8349
infernus8349OPā€¢2y ago
So how can i use threadpooling i checked online and this was what was shown 0_0
mtreit
mtreitā€¢2y ago
Tasks use the thread pool automatically
infernus8349
infernus8349OPā€¢2y ago
oh[ 0_0
mtreit
mtreitā€¢2y ago
Also Thread.Sleep ree
infernus8349
infernus8349OPā€¢2y ago
but some articles said it does not then? šŸŸ”
mtreit
mtreitā€¢2y ago
Why are you sleeping?
infernus8349
infernus8349OPā€¢2y ago
oh, because i had some Console.WriteLine() statements there which i didn't add here as i thought it wasn't necessary so the 2 seconds gives me enough time to read
mtreit
mtreitā€¢2y ago
Ok, I guess that's in your Main function so maybe it doesn't matter. You can use async and await Task.Delay instead as a preferred approach, but again maybe here it doesn't matter. Thread.Sleep is usually a mistake though.
infernus8349
infernus8349OPā€¢2y ago
anyway , in the thread you were mentioning how will you make it more optimised can you show me the optimised one
mtreit
mtreitā€¢2y ago
Not sure what you mean The code you posted doesn't appear to do I/O Also I'm reading this on my phone...
infernus8349
infernus8349OPā€¢2y ago
like instead i wrote the fucntion Produce like this, please let me know if this is optimal or not
public void Produce(random_class ware)
{

//ThreadPool.QueueUserWorkItem(new WaitCallback(Consume), ware);

Thread t = new Thread(Consume);
t.Start(ware);

QueueLength++;
}
public void Produce(random_class ware)
{

//ThreadPool.QueueUserWorkItem(new WaitCallback(Consume), ware);

Thread t = new Thread(Consume);
t.Start(ware);

QueueLength++;
}
omg, sorry i dind't know you were on the phone this does not, this is not the main code, this is just learning code that i am testing on
mtreit
mtreitā€¢2y ago
new Thread Nooooo
infernus8349
infernus8349OPā€¢2y ago
then?
mtreit
mtreitā€¢2y ago
Tasks. Use Tasks.
infernus8349
infernus8349OPā€¢2y ago
oh
mtreit
mtreitā€¢2y ago
Definitely watch the talk first I think it covers everything in a way that will hopefully show the difference between using explicit thread objects vs tasks
infernus8349
infernus8349OPā€¢2y ago
fine, i will listen to it, i will ping you if i need any more help šŸ™‚
mtreit
mtreitā€¢2y ago
šŸ‘
infernus8349
infernus8349OPā€¢2y ago
i used task and now it is running at 3.3GB with 25 threads and yes you were right, it is using threadpooling i just ran with this task thing you said, the previous code with QueueUserWorkItem() finished in 00:06:08 UnsafeQueueUserWorkItem() finished in 00:05:36 var t = Task.Run() finished in 00:06:49 Task.Run() finished in 00:06:46 there is a difference of 38 seconds between QueueUserWorkItem() and Task.Run() and i do believe you have mentioned that they both use threadpooling so why this major difference in the performance? i mean 38 seconds is a huge difference
mtreit
mtreitā€¢2y ago
I would have to see a complete code sample that reproduced the issue...that really doesn't sound right. Also what are you doing that takes minutes? Usually we are talking microseconds or maybe milliseconds. Even for very large datasets A proper benchmark using BenchmarkDotNet is a good starting point I feel like one of your implementations is doing something significantly different than the other Task.Run should essentially be the equivalent of QueueUserWorkItem, period.
infernus8349
infernus8349OPā€¢2y ago
this is the code the function Produce contain 4 lines of code which are commented only one should be run at a time and you can find the performance difference i have mentioned by CPU and RAM specs
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
infernus8349
infernus8349OPā€¢2y ago
FYI, using QueueUserWorkItem() and UnsafeQueueUserWorkItem caused a heavy spike in ram usage and it reached to 1.4 GB (approx) but the other two codes have a gradual increase in the usage of ram until it caps at 3.4 GB (approx) but then it reduces later i dont understand
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
infernus8349
infernus8349OPā€¢2y ago
i see, but lets get back to the performance change there is a considerable difference can you spot the reason why?
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
infernus8349
infernus8349OPā€¢2y ago
i will be afk for a bit, will respond to you soon for your analysis on this. i do believe the comments explain what to do
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
infernus8349
infernus8349OPā€¢2y ago
what wait? but i did put the comments in the Produce function
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
infernus8349
infernus8349OPā€¢2y ago
there are 8 commented lines out of the 8, 4 shows the time other 4 are codes where you shoudl be using 1 at a time while running
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
infernus8349
infernus8349OPā€¢2y ago
to get the results
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
infernus8349
infernus8349OPā€¢2y ago
its literally a txt file, you can just download it 0_0 i gtg now, will be back soon
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
infernus8349
infernus8349OPā€¢2y ago
now you see all the comments igtg now , will be back
Kouhai
Kouhaiā€¢2y ago
As ToBe said, -- and ++ aren't thread safe Your while (obj.QueueLength != 0) might even keep running infinitely
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
mtreit
mtreitā€¢2y ago
Right out of my talk šŸ¤—
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
mtreit
mtreitā€¢2y ago
I haven't seen this one, but strangeloop is usually great...will have to check it out
Accord
Accordā€¢2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
infernus8349
infernus8349OPā€¢2y ago
@mtreit i did watch it and i have dropped a comment on it. one of the solutions you have done to be thread safe is being less thread safe for me. i have explained it in the youtube comments, please take a look at that. . i have put a reply . for the link of your video so that you can reach the link easily i tried watching this buy i cannot understand with all this percentile talks. I got totally confused.
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
mtreit
mtreitā€¢2y ago
It's unclear from your YouTube comment what exactly you are referring to...can you share the exact code in question?
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
mtreit
mtreitā€¢2y ago
And no answer
infernus8349
infernus8349OPā€¢2y ago
yes ofcourse i will sorry as i normally dont use discord much i will send you the code right now I just tried it again the codes but now i am getting totally a different result now its showing as expected before when i messaged you about it, this code was giving me like 999 and 1000
class Program
{
static int _totalProcessed = 0;

static void Main(string[] args)
{
int numTasks = 1000;
var tasks = new Task[numTasks];

for (int i = 0; i < numTasks; i++)
{
var task = Task.Run(() =>
{
_totalProcessed++; //even this is not thread safe
});

tasks[i] = task;
}

Task.WaitAll(tasks);

Console.WriteLine($"totalProcessed: {_totalProcessed}.");
}
}
class Program
{
static int _totalProcessed = 0;

static void Main(string[] args)
{
int numTasks = 1000;
var tasks = new Task[numTasks];

for (int i = 0; i < numTasks; i++)
{
var task = Task.Run(() =>
{
_totalProcessed++; //even this is not thread safe
});

tasks[i] = task;
}

Task.WaitAll(tasks);

Console.WriteLine($"totalProcessed: {_totalProcessed}.");
}
}
and the solution gave a range of result from 995 till 999 here is the solution code
class Program
{
static int _totalProcessed = 0;

static void Main(string[] args)
{
int numTasks = 1000;
var tasks = new Task[numTasks];

for (int i = 0; i < numTasks; i++)
{
var task = Task.Run(() =>
{
Interlocked.Increment(ref _totalProcessed); //now this is thread safe (idk why its not being thread safe)
});

tasks[i] = task;
}

Task.WaitAll(tasks);

Console.WriteLine($"totalProcessed: {_totalProcessed}.");
}
}
class Program
{
static int _totalProcessed = 0;

static void Main(string[] args)
{
int numTasks = 1000;
var tasks = new Task[numTasks];

for (int i = 0; i < numTasks; i++)
{
var task = Task.Run(() =>
{
Interlocked.Increment(ref _totalProcessed); //now this is thread safe (idk why its not being thread safe)
});

tasks[i] = task;
}

Task.WaitAll(tasks);

Console.WriteLine($"totalProcessed: {_totalProcessed}.");
}
}
but now when i ran, the results just interchagned I am not sure why that was happening
D.Mentia
D.Mentiaā€¢2y ago
That's... exactly what he explains in the video It could be any number because of the closure problem that he explains
mtreit
mtreitā€¢2y ago
This isn't the closure / variable capture issue. But anyway yes I don't understand the question as this appears to be showing the exact thing I demonstrated about integer increment not being thread safe and why you need to use something like Interlocked.Increment
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
D.Mentia
D.Mentiaā€¢2y ago
oh. Well in that case it's probably something to do with the Task.WaitAll vs await Task.WhenAll
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
Accord
Accordā€¢2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
infernus8349
infernus8349OPā€¢2y ago
exactly Like even after doing the threadsafe method, that day the threads were more unsafe than the unsafe method idk why but when i ran it on 17th december, it was being threadsafe i ma not sure why this change of behaviour when the code never changed
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
infernus8349
infernus8349OPā€¢2y ago
oh i see that could be the reason
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
MODiX
MODiXā€¢2y ago
D.Mentia#0614
It could be any number because of the closure problem that he explains
Quoted by
<@!689473681302224947> from #ā” ThreadPooling (click here)
React with āŒ to remove this embed.
Unknown User
Unknown Userā€¢2y ago
Message Not Public
Sign In & Join Server To View
infernus8349
infernus8349OPā€¢2y ago
I see Fine i will cehck it if you are good in system.reflection, can you help me iwth this post https://discord.com/channels/143867839282020352/1056469510376407070/1056469510376407070
MODiX
MODiXā€¢2y ago
infernus#8349
So I got a dll file that contains a class and its interface. What I want is to extract the class as an item than an instance. So for example, if I have a dynamic variable of name "temp" and I wish to put the class which I extracted from dll by looping over GetExportedTypes() of the particular Assembly and putting value into "temp" when I get the preferred class, I want to be able to use it like temp instance_of_clas = new temp(); like that, is that possible? if so, how to do it? if not, is there any alternative method (other than using Activator.CreateInstance()). My aim is not to get the instance, my aim is to get the class in such a way that I can create an instance using it.
Quoted by
<@!455720889196216331> from #System.Reflection (click here)
React with āŒ to remove this embed.
Want results from more Discord servers?
Add your server