Recently more idle, (the project to turn Java was divided into architecture group, marginalized personnel, nothing to do hahahaha)
NET Framework used some time ago to record the .Utilize multi-core CPUs with parallel strategiesOne way to optimize
The reason is that there is a billing method in the project, which needs to summarize a month's worth of data in memory for calculation, statistics, grouping, and then generating new data.
Deployed in a customer, found that the implementation of this method is very inefficient, monitoring the data found from the database query out very quickly (because the database is a separate server)
Then I checked the server's CPU via top and it went to 100%. RAM is fine, checked the CPU model emm... It sucks, but the good thing is that it has a lot of cores (after all, it's a server-grade U)...
The server core count is at 16. If you look at Linux with the top command, the CPU is theoretically 1600% full, but the program is only eating a single core.
It's like 1 person working and 15 people eating... Picture.
Then looked at the code, found that the calculation of the settlement of the piece of code in a single foreach for sequential calculations, so decided to use the .NET provides a parallel task library (TPL) to optimize .
After the optimization, we went from having thread timeouts due to settlement to settling in about 20 seconds. That's a huge improvement.
1 Introduction to Parallel Programming in .NET
In today's world of rapid hardware development. Too many personal computers and server-class CPUs have multiple CPU cores in order to facilitate multiple threads to be able to execute at the same time. By taking full advantage of the hardware, it is possible to parallelize code using parallel programming in order to spread the work across multiple processors.
Previously, parallelization required opening sub-threads, maintaining locks, and other tedious operations. But the introduction of the TPL in the .NET Framework 4 has simplified parallel development. With a few simple modifications, you can write efficient, fine-grained, and scalable parallel code without having to deal directly with threads or thread pools.
The following screenshot from the official documentation briefly illustrates the parallel programming architecture in .
We can see that Parallel adds a layer of encapsulated algorithms on top of the thread handling, making it easier to handle parallel multithreading.
2. Parallel task library (TPL)
The Task Parallel Library (TPL) is cap (a poem) A set of public types and APIs in the space.
The purpose of the TPL is to increase developer productivity by simplifying the process of adding parallelism and concurrency to applications.
TPL dynamically scales the degree of concurrency to make the most efficient use of all available processors.
In addition, TPL handles work partitions,ThreadPool on thread scheduling, cancel support, state management, and other low-level detail operations.
By using the TPL, you can maximize the performance of your code while focusing on what the program is trying to accomplish.
(The above is from the official document, I think it is already very detailed)
So let's write an example of a parallel task and see how it works.
First of all, the Parallel Task Library provides two methods, one and one, which are similar to each other, so let's experiment with them.
First create two methods with the following code.
//Creating Sequential Execution Methods static List<dynamic> AddModelSequential(int modelCount) { var list = new List<dynamic>(); //To increase the complexity of the loop, a loop is nested inside it. for (int i = 0; i < modelCount; i++) { int f = 0; for (int j = 0; j < 5000; j++) { f++; } (new { bbb = i, aaa = "1", ccc = f }); } return list; } //Creating Parallel Execution Methods static List<dynamic> AddModelParallel(int modelCount) { var list = new List<dynamic>(); (0, modelCount, i => { int f = 0; //To increase the complexity of the loop, a loop is nested inside it. for (int j = 0; j < 5000; j++) { f++; } (new { bbb = i, aaa = "1",ccc= f}); }); return list; }
Then execute two methods, both run 10W data, and record the execution time. As follows.
static void Main(string[] args) { ("perform sequential loops..."); Stopwatch stopwatch = new Stopwatch(); (); AddModelSequential(1000000); (); ("Sequential loop time (milliseconds): {0}", ); (); ("Execute parallel loops..."); (); AddModelSequential(100000); (); ("Parallel loop time (milliseconds): {0}", ); (); }
I have an I9 12th generation CPU with 20 logical processors, and I get the following results.
A 20-fold increase in performance...
Due to the development machine to run more things, for the CPU usage, monitoring is not very clear, we pulled out ... Aliyun 99 yuan free shipping 2-core 2G server.... Let's take a look at the effect.
We can clearly see that on a 2-core machine there's probably close to a doubling of performance as well.
By using the top command, you can obviously listen to the CPU usage.
When running the first loop, the CPU is 100% and the single core is full, as shown here.
When running the second loop, the second CPU starts to get involved, as shown in the following figure.
So under the right circumstances (note that this is the right circumstances)
The use of parallel task libraries in the program makes full use of the multi-core performance of the server, which can lead to a significant improvement in operational efficiency.
3. Parallel PLINQ
PLINQ is a set of extensions to LINQ.
It allows queries to be executed in parallel on collections supporting the IEnumerable<T> interface using multiple processors or cores on the computer on which the code is running.
This can significantly reduce the time required to process large data sets or perform complex calculations
Note that here you can see that PLINQ only supports IEnumerable interface, so linq to sql expression tree is not supported, if you use it will lead to the full table query to memory
The way to use it is also very simple, just add the AsParallel method before the dataset is processed, as follows.
//LINQ var results = from item in dataSource where () select (); //PLINQ var parallelResults = from item in () where () select ();
PLINQ is used in a very specific scenario.So far in the demo I haven't reflected that it's faster than LINQ (even LINQ is much faster than PLINQ).
So we must consider the following when we use it.
- Not always faster: While PLINQ can arguably improve the performance of some complex queries, not all operations will see significant gains. The overhead incurred by thread management and synchronization can sometimes make PLINQ queries slower than their sequential counterparts, especially for small datasets or operations of low computational complexity.
- Overhead: Parallelization introduces overheads, such as task scheduling and switching between threads. For small collections or operations that are not CPU-intensive, these overheads may offset the benefits of parallelization, making PLINQ queries slower than standard LINQ queries.
- Sorting: By default, PLINQ does not guarantee the order of results. If ordering is important, the AsOrdered or OrderBy methods can be used, but this may further reduce the performance gains from parallelization.
To summarize, if you want to use PLINQ, you must fully test and evaluate the performance, and you must make sure that PLINQ has a big improvement before you use it.
.