Learning TPL (1)

Source: Internet
Author: User

Vs2010 has been released this week.ArticleAll of them are showing new vs2010 experiences. Here I am also sharing the excitement and writing.

What is TPL?

TPL is short for task parallel library, which is one of the newly added class libraries in framework 4.0. The most famous class libraries are Plinq (speaking of Plinq, you will know in an instant ). However, Plinq only provides the most commonly used content to users using the LINQ compatible syntax for ease of use. Therefore, many advanced TPL functions cannot be implemented using Plinq, this is one of the important reasons for learning TPL.

Simple Example

Let's talk about TPL, a super complicated thing. Let's start from the example at. Otherwise, I don't know what I'm talking about after reading it.

Now let's assume that we want to calculate the factorial between 1 and 20 (in the long range, we don't need to process large numbers), and we want to write a line "x completed" when each computation is complete ", finally, the calculation results are output in the order of 1-20.

Therefore, there are two stages. The first stage is computing + output computing, and the second stage is output computing results in order.

Synchronous implementation

If synchronous implementation is used,CodeIt will be like this:

  long  [] Results =  New   long  [20]; 
for ( int I = 0; I <20; I ++)
{< br> long x = 1;
for ( int j = 1; j <= I; j ++)
{< br> X * = J;
}< br> results [I] = x;
console. writeline (I + "computing completed" );
}< br> for ( int I = 0; I <20; I ++)
{< br> console. writeline (results [I]);
}

It's easy, right. If you use LINQ, it will become like this:

  foreach  (VAR result  in  (from I  in  enumerable. range (0, 20) 
select New func long (() >>< BR >{< br> long x = 1;
for ( int j = 1; j <= I; j ++)
{< br> X * = J;
}< br> console. writeline (I + "computing completed" );
return X;
})()). tolist ()
{< br> console. writeline (result);
}

Of course, we can further improve the write elegance of LINQ. However, these pretty nice-looking LINQ code will not affect the subsequent experiments.

Let's take a look at the results:

0 completed
1. Computing completed
2 computing completed
3. Computing completed
4. Computing completed
5. Computing completed
6. Computing completed
7. Computing completed
8. Computing completed
9 computing completed
10 completed computing
11 computing completed
12. Computing completed
13 computing completed
14 computing completed
15 computing completed
16 computing completed
17 computing completed
18 computing completed
19. Computing completed
1
1
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000

There is nothing to elaborate on a very sequential execution result.

Plinq implementation

With the above LINQ implementation, we can easily translate it into Plinq implementation:

  foreach  (VAR result  in  (from I  in  parallelenumerable. range (0, 20) 
select New func long (() >>< BR >{< br> long x = 1;
for ( int j = 1; j <= I; j ++)
{< br> X * = J;
}< br> console. writeline (I + "computing completed" );
return X;
})()). tolist ()
{< br> console. writeline (result);
}

Are there any differences? Replace enumerable. range with parallelenumerable. Range,

Let's take a look at the running results:

0 completed
10 completed computing
11 computing completed
12. Computing completed
13 computing completed
14 computing completed
15 computing completed
16 computing completed
17 computing completed
18 computing completed
19. Computing completed
1. Computing completed
2 computing completed
3. Computing completed
4. Computing completed
5. Computing completed
6. Computing completed
7. Computing completed
8. Computing completed
9 computing completed
1
1
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000

It can be found that the calculation process is out of order (although not completely out of order), but the output is in order.

Do you still remember the extension method asparallel? Use that to implement a look:

  foreach  (VAR result  in  (from I  in  enumerable. range (0, 20 ). asparallel () 
select New func long (() >>< BR >{< br> long x = 1;
for ( int j = 1; j <= I; j ++)
{< br> X * = J;
}< br> console. writeline (I + "computing completed" );
return X;
})()). tolist ()
{< br> console. writeline (result);
}

What is the difference? It looks like it is similar. In fact, you only know when you run it:

0 completed
2 computing completed
3. Computing completed
4. Computing completed
1. Computing completed
6. Computing completed
7. Computing completed
8. Computing completed
9 computing completed
10 completed computing
5. Computing completed
12. Computing completed
13 computing completed
14 computing completed
15 computing completed
16 computing completed
17 computing completed
18 computing completed
19. Computing completed
11 computing completed
1
720
5040
40320
362880
3628800
39916800
1
2
6
24
120
479001600
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000

The calculation is out of order, but the output is out of order. This is a little different from the target, so you need to correct it again:

Foreach(VAR resultIn(From IInEnumerable. Range (0, 20). asparallel (). asordered ()
SelectNewFunc <Long> () =>
{
LongX = 1;
For(IntJ = 1; j <= I; j ++)
{
X * = J;
}
Console. writeline (I +"Computing completed");
ReturnX;
}) (). Tolist ())
{
Console. writeline (result );
}

This time I added an asordered after asparallel. We need to set the concurrency order. It sounds like a detour. Let's look at the execution result:

0 completed
1. Computing completed
2 computing completed
3. Computing completed
4. Computing completed
5. Computing completed
6. Computing completed
7. Computing completed
8. Computing completed
10 completed computing
11 computing completed
12. Computing completed
13 computing completed
14 computing completed
15 computing completed
16 computing completed
17 computing completed
18 computing completed
19. Computing completed
9 computing completed
1
1
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000

We can see that the execution process is out of order (note 9), but the overall trend is in order, but what matters is that the output is indeed in order.

Basic Application of TPL

As mentioned in the article at the beginning, Plinq only encapsulates the most common parts of TPL into the LINQ syntax, but there are still many advanced functions, which do not lack the two-phase processing required in the example.

However, several concepts need to be introduced:

The first is a task. In TPL, a task is the core part (or how can it be called the task parallel library). A task is used to encapsulate an operation, make it an inseparable unit in TPL, that is, the TPL executor allocates and executes tasks as the basic unit.

The second is taskfactory. You can see what the name is...

Too abstract? It is indeed abstracted. Let's see how to implement it using task and taskfactory:

 
Taskfactory TF =NewTaskfactory ();
VaR T = TF. continuewhenall (
(From IInEnumerable. Range (0, 20)
Select TF. startnew () =>
{
LongX = 1;
For(IntJ = 1; j <= I; j ++)
{
X * = J;
}
Console. writeline (I +"Computing completed");
ReturnX;
}). Toarray (),
Tasks =>
{
Foreach(VAR taskInTasks)
Console. writeline (task. Result );
});
T. Wait ();

There are two types of tasks. The first type of tasks is created using the startnew method of taskfactory. The second type is created by taskfactory using the continuewhenall method, used to output results.

If necessary, use the wait method of the task to wait for the task to be executed (see the last line of the Code ).

When creating the first batch of tasks, it is not difficult to find that a standard LINQ is used directly. In fact, this is only a task creation, so it does not actually execute the computation. So let's take a look at the output result:

0 completed
1. Computing completed
2 computing completed
3. Computing completed
4. Computing completed
6. Computing completed
7. Computing completed
8. Computing completed
9 computing completed
10 completed computing
11 computing completed
12. Computing completed
13 computing completed
14 computing completed
15 computing completed
16 computing completed
17 computing completed
18 computing completed
19. Computing completed
5. Computing completed
1
1
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000

It is found that the calculation part is not sequential, but there is a problem. Why is the result similar to asorder? In general, it still tends to be sequential?

This is because the amount of computing is too small, so there is a certain deficiency in data discretization, so the calculation part of the code is replaced:

LongX = 1;
For(IntY = 0; y <10000000; y ++)
{
X = 1;
For(IntJ = 1; j <= 19-I; j ++)
{
X * = J;
}
}
Console. writeline (I +"Computing completed");
ReturnX;

In this way, the calculation amount is increased, and the calculation amount decreases with the increase of I.

Re-run the detection calculation order:

0 completed
1. Computing completed
3. Computing completed
2 computing completed
5. Computing completed
4. Computing completed
6. Computing completed
7. Computing completed
8. Computing completed
11 computing completed
10 completed computing
9 computing completed
12. Computing completed
15 computing completed
13 computing completed
16 computing completed
17 computing completed
19. Computing completed
14 computing completed
18 computing completed

It is also found that TPL is actually run using two threads (because the local machine is dual-core, for pure computing, excessive threads cannot help usProgramIt runs faster, but will lose some performance due to the back-and-forth switching of thread context). So those tasks are only waiting in queue and wait until the previous task ends (unless the previous task is blocked, TPL will add more threads for execution), which is an important reason for the overall trend in order.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.