dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.95k stars 4.65k forks source link

Idle thread timeout rules for thread pools #107017

Closed zhenlei520 closed 1 week ago

zhenlei520 commented 2 weeks ago

I want to change the timeout of the idle thread in the thread pool. How should I control this?

I hope to increase MinThreads and increase the timeout of the idle thread to deal with the impact of the thread pool creating threads on the CPU when the burst traffic increases. But I can't find how to change the timeout rule for this idle thread

dotnet-policy-service[bot] commented 2 weeks ago

Tagging subscribers to this area: @mangod9 See info in area-owners.md if you want to be subscribed.

kouvel commented 2 weeks ago

I want to change the timeout of the idle thread in the thread pool. How should I control this?

The timeout can be changed with the ThreadTimeoutMs setting with an environment variable or with an AppContext config var.

There's also a setting to keep a minimum number of threads alive (ThreadsToKeepAlive).

zhenlei520 commented 2 weeks ago

ThreadTimeoutMs

I'm glad to receive your reply

I tried to change the timeout according to the above configuration, but it didn't work. In the local test, the thread pool started to recycle after 80 seconds. The example code is as follows

ConsoleApp1.zip

Thread Start!
ThreadPool Min: 8 1
ThreadPool Max: 32767 1000
Please enter the minimum number of threads
200
Set Min Threads:200, Status:True
Please enter the maximum number of threads
500
Set Max Threads:500, Status:True
Time | Threads | TotalThreads | Running | Pending
-----+---------+---------+---------
  0s |       8 |     26|      15 |     184
  1s |     136 |    150|     135 |      64
  2s |     202 |    215|     200 |       0
  3s |     202 |    215|     200 |       0
  4s |     202 |    215|     200 |       0
  5s |     202 |    215|     200 |       0
  6s |     202 |    215|     200 |       0
  7s |     202 |    215|     200 |       0
  8s |     202 |    215|     200 |       0
  9s |     202 |    215|     200 |       0
 10s |     202 |    215|     200 |       0
 11s |     202 |    215|     200 |       0
 12s |     202 |    215|     200 |       0
 13s |     202 |    215|     200 |       0
 14s |     202 |    215|     200 |       0
 15s |     202 |    215|     200 |       0
 16s |     202 |    215|     200 |       0
 17s |     202 |    215|     200 |       0
 18s |     202 |    215|     200 |       0
 19s |     202 |    215|     200 |       0
 20s |     202 |    215|     200 |       0
 21s |     202 |    215|     200 |       0
 22s |     201 |    214|     200 |       0
 23s |     201 |    214|     200 |       0
 24s |     201 |    214|     200 |       0
 25s |     201 |    214|     200 |       0
 26s |     201 |    214|     200 |       0
 27s |     201 |    214|     200 |       0
 28s |     201 |    214|     200 |       0
 29s |     201 |    214|     200 |       0
 30s |     201 |    214|     200 |       0
 31s |     201 |    214|     200 |       0
 32s |     201 |    214|     200 |       0
 33s |     201 |    214|     200 |       0
 34s |     201 |    214|     200 |       0
 35s |     201 |    214|     200 |       0
 36s |     201 |    214|     200 |       0
 37s |     201 |    214|     200 |       0
 38s |     201 |    214|     200 |       0
 39s |     201 |    214|     200 |       0
 40s |     201 |    214|     200 |       0
 41s |     201 |    214|     200 |       0
 42s |     201 |    214|     200 |       0
 43s |     201 |    214|     200 |       0
 44s |     201 |    214|     200 |       0
 45s |     201 |    214|     200 |       0
 46s |     201 |    214|     200 |       0
 47s |     201 |    213|     200 |       0
 48s |     201 |    214|     200 |       0
 49s |     201 |    214|     200 |       0
 50s |     201 |    214|     200 |       0
 51s |     201 |    213|     200 |       0
 52s |     201 |    213|     200 |       0
 53s |     201 |    214|     200 |       0
 54s |     201 |    214|     200 |       0
 55s |     201 |    214|     200 |       0
 56s |     201 |    214|     200 |       0
 57s |     201 |    214|     200 |       0
 58s |     201 |    214|     200 |       0
 59s |     201 |    214|     200 |       0
 60s |     201 |    214|     131 |       0
 61s |     201 |    214|      36 |       0
 62s |     201 |    214|       0 |       0
 63s |     201 |    214|       0 |       0
 64s |     201 |    214|       0 |       0
 66s |     201 |    214|       0 |       0
 67s |     201 |    214|       0 |       0
 68s |     201 |    214|       0 |       0
 69s |     201 |    214|       0 |       0
 70s |     201 |    214|       0 |       0
 71s |     201 |    214|       0 |       0
 72s |     201 |    214|       0 |       0
 73s |     201 |    214|       0 |       0
 74s |     201 |    213|       0 |       0
 75s |     201 |    213|       0 |       0
 76s |     201 |    213|       0 |       0
 77s |     201 |    213|       0 |       0
 78s |     201 |    213|       0 |       0
 79s |     201 |    213|       0 |       0
 80s |     201 |    213|       0 |       0
 81s |     120 |    150|       0 |       0
 82s |      28 |     41|       0 |       0
 83s |       1 |     14|       0 |       0
 84s |       1 |     14|       0 |       0
 85s |       1 |     14|       0 |       0
 86s |       1 |     13|       0 |       0
 87s |       1 |     13|       0 |       0
kouvel commented 2 weeks ago

I tried to change the timeout according to the above configuration, but it didn't work. In the local test, the thread pool started to recycle after 80 seconds. The example code is as follows

I just tried it and it seems to be working as expected on .NET 8, when either config var is set to -1, the thread pool threads stay and don't time out. In .NET 6, the config vars are available from runtime version 6.0.25.

Although setting the config vars as in the example should work for this example, they are read only one time when the thread pool is first used, which could be very early in some cases. It would be better to set the environment variables in the shell before starting the process, or to set the AppContext settings in the *.runtimeconfig.json. Also if both the environment variable and AppContext settings are set, the environment variable setting is used.

zhenlei520 commented 1 week ago

I tried to change the timeout according to the above configuration, but it didn't work. In the local test, the thread pool started to recycle after 80 seconds. The example code is as follows

I just tried it and it seems to be working as expected on .NET 8, when either config var is set to -1, the thread pool threads stay and don't time out. In .NET 6, the config vars are available from runtime version 6.0.25.

Although setting the config vars as in the example should work for this example, they are read only one time when the thread pool is first used, which could be very early in some cases. It would be better to set the environment variables in the shell before starting the process, or to set the AppContext settings in the *.runtimeconfig.json. Also if both the environment variable and AppContext settings are set, the environment variable setting is used.

Thank you very much. By setting the environment variables in the shell and then starting the program, the thread pool no longer recycles threads.