Advanced_C#_Skill_Task Parallel Library_vs_Lambda Expressions_任務和線程差在哪裡?線程池又是捨麼??
在我們了解Task之前
對於多線程,我們經常使用的是Thread
如果我們要使用多核的功能可能就會自己來開線程,
然而這種線程模型在.net 4.0之後被一種稱為基於「任務的編程模型」所沖擊,
原因在於 task會比thread所需消耗的性能來的更小
不過大家肯定會有疑惑,任務和線程到底有什麽區別呢?
Threads(線程/執行緒)
Threads are real OS thread with own its stack and resources. Threads allow to developer be fully controlled (by using Resume(), Suspend() or Abort() and etc). The problem is that threads are "time hungry" entities, which means that they will consume non trivial time at creation stage. In additional we should take in consideration time for context switching overhead performed by CPU.
Task(任務)
Task is class introduces as part of TPL [Task Paralel Library] and it came with CLR 4.0. Task represent compromise of above cases. It relays on TaskScheduler which in his turn working against ThreadPool.
Task able to return result after it completes (unlike ThreadPool). In addition we can run another task immediately when first one is completes.
Let us first understand the relationship between task and thread. See the following figure.
Typically task is resided(存在于) in a thread.
A task may contain one or more child tasks those are not necessarly resided in the parent task’s thread. In the above figure, Child Task M2 of Task M resided in Thread B.
Task(任務) 和 Thread(線程/執行緒) 的區別:
1、Task是架構在Thread之上的,也就是說Task最終還是要拋給Thread去執行。
2、 Task(任務)跟Thread(線程/執行緒)不是一對一的關系,
比如開10個任務並不是說會開10個線程,
這一點任務有點類似線程池(ThreadPool),
但是任務相比線程池有很小的開銷和精確的控制。
ThreadPool
ThreadPool is entity that optimize overheads of the threads and it manage them [threads] by itself. In return it gives developer small maneuver possibilities such as pool size and ability to submit work to execute at some point. And thats it!
在多線程編程中,線程的創建和銷毀是非常消耗系統資源的,
因此,C#引入了池的概念,維護一個池,
池內維護的一些線程,需要的時候從池中取出來,
不需要的時候放回去,這樣就避免了重複創建和銷毀線程。
自己一開始對這個名詞的解釋及感覺
線程池 給我的感覺很像一個魚塭或者一個養魚的魚池
一個大池塘裏頭存放了很多給我們吃的魚
我們一個人就好比為一種應用程式
我們都知道應用程式在運行時會消耗資源
這裡我就比喻為工作上班或者讀書讀到很晚
你餓了累了需要吃一點池子裡的魚你才能繼續工作讀書奮鬥
你有需要再去取魚 這就是一個 ThreadPool的比較生活化的比擬
池子中一條條的魚就好比為一條條的 Thread 線程
用來供應我們蛋白質或者豐富的DHA 而這些在電腦世界中我們稱之為資源(Resource)
可是這個比喻並不好因為魚被吃掉就消化掉了
並不能重複利用
並不能再丟到池子裏頭
前陣子在台北有做過Uber
覺得Uber是個可以解釋的例子
假設我說台北區域包含了一堆Uber的汽車
台北居民人手一支手機,手機當中有叫Uber的App
那我就說充斥著Uber的台北這塊區域是一個"Uber的池子"
當我需要我就叫Uber不需要Uber就回去池子中洄游
這個比擬感覺比較OK 雖然可能跟一般教科書或者程式課本、論壇上
比較死版、八股的定義上比起來會有些許差異
但是大概80%是可以被接受的
Thread Pooling
Thread pooling is the process of creating a collection of threads during the initialization of a multithreaded application, and then reusing those threads for new tasks as and when required, instead of creating new threads.
Then every process has some fixed number of threads depending on the amount of memory available, those threads are the need of the application but we have freedom to increase the number of threads.
(1).Every thread in the pool has a specific given task.
(2).The thread returns to the pool and waits for the next assignment
when the given task is completed.
Usually, the thread pool is required when we have number of threads are created to perform a number of tasks, in this organized in a queue. Typically, we have more tasks than threads.
As soon as a thread completes its task, it will request the next task from the queue until all tasks have been completed. The thread can then terminate, or sleep until there are new tasks available.
One of the typically more complicated topics to understand within any sort of language
but in your development career that you're going to run into probably
(很可能;大概)
and that has to do with parallel or asynchronous programming which really just at
(異步的)
the end of the day means I want to be able to execute multiple instructions on a CPU or
on multiple core CPUs at the same time.
In previous versions of dot Net and C sharp
we were forced to do this through the system that threading namespace
and while this was able to get the job done it required us to write a lot of
overhead code in order to create these threads spawn them off have them execute some
spawn 閃靈悍將 、 大量產生--->翻譯有待修改
sort of operations checck when they're done pass into them some sort of delegates or something
(一半一半,說話沒有十足把握時用 sort of 或 kind of 來緩和語氣)
of that nature to execute when they were done or function pointers to executewhen they were done and so there was a lot of overhead there that we were really required
to do in order to just really get things going and then heaven forbid you had to do any sort
of synchronization and making sure that you're letting go of resources
when you're supposed to not having any deadlocks and things of that nature really
got to be quite a mess and really a headache to maintain and really a lot of people
shied away from it because of that
(因不喜歡、害怕或缺乏自信而)退縮,躲避,畏避
also one of the bigger problems with using raw treads in that way is
that it is possible if you are running on an older machine and you simply had a single
single core processor and you try to spin up a bunch of extra threads
(單核心處理器) (加快運轉) (一束、一串)
to try to run several operations at the same time you could really overloaded
(同時地) (超載)
actually to the detriment of your application cause a lot of context switching
(不利、損失) (內文切換)
當CPU從一個process切到另一個process執行之前,OS必須保存原有process的執行狀態,
同時載入New Process的執行狀態
Context switching是一系統負擔,其時間長短,幾乎完全取決於Hardware因素
利用Thread(light-weighted process)來取代process
得以降低context switching負擔
on the CPU between those threads because it was trying to execute them
as parallel as possible but since there was only one core could only execute one
instruction at a time and had to switch between them so that is very
(指示,命令)
costly to your CPU , is very costly to your system and actually why is that
typically slowing down your performance .
(效能)
Microsoft took a lot of these things back to the drawing board
and said how can we improve this how can we give our developers
the opportunity to continue to write asynchronous code or code that can be run
in parallel but get rid of a lot of headache and make it more intuitive to how they were
(擺脫) (憑直覺獲知的、直覺的)
typically write code today
In this lesson , I'm going to take you through the Task Parallel Library
or TPL and show you how tasks are able to alleviate a lot of stress and a lot of the
(減輕,使緩和) (壓力)
problem with writing parallel code and allow you to do it quite easily.
=============================================================
New a console application at first!!!
Now I do have to do a little bit of setup here as you know in the previous lessons
I turn to write some code and then I'll hit the Ctrl+F5 and that really
runs the application in debug mode so that there is a line at the end of the console
application waiting for you to hit any key at that point it's kind of blocked all of the executions
of any other tthreads or anything going on in the background and we're not able to see anything
else execute so in order for me to properly show you some of these techniques
and I want to show you we're going to have to shy away from the debugging aspect
and using Ctrl+F5 and just write our own sort of stopper at the end of the application
so we can stop the console application from finishing but still allow
us to see some code being executed on other threads other tasks
in order to do that I'm simply going to drop down a few lines here and I'm going to a
Console.WriteLine and right in here a press any key to quit so
this is really going to serve the same purpose as the Ctrl+ F5
and After someone going to say Console ReadKey which going to sit here and
wait for keyboard input from the user and it will sit here not blocking waiting for me to
press anything on the keyboard so if I hit F5 at this point
you're going to see press any key to quit
it will sit here indefinitely I can hit any can hear hit
this is going to allow me o write a little bit more code
so you can see things execute as we go
======================================================================
So what does the TPL of the Task Parallel Library do for us
that threading couldn't do or are how do we actually use these tasks
in this library for us well it's quite simple actually so the first thing I want to do
is I want to create a task
I want to call this t1 and I want to say this is equal to a new task
If you see here there's
a number of overloads but the most common one at least for this course is
going to be the action and if you recall from our lessons on delegates anonymous method
and lambda expressions this is merely a generic delegate and since there is
no generic parameterize type on this action that means there are no inputs to this
在 C# 2.0 以前的版本中,宣告委派 (Delegate) 的唯一方式是使用具名方法。 C# 2.0 引進了匿名方法 (Anonymous Method),在 C# 3.0 (含) 以後版本,則以 Lambda 運算式取代匿名方法來做為撰寫內嵌 (Inline) 程式碼的慣用方式。
Lambda 運算式 Syntatic sugar
分三部分
Left-hand side
(1).Parameter(s) that can be 0 , 1 or more parameters ....
Center
(2). => "equals greater than" sign means "goes to" operator is also called the lambda operator
Right-hand side
(3).Expression or a series of Statements
Expression Lambda
Left-hand side Center Right-hand side
( Person person ) => person.FirstName == "Sam"
Statement Lambda
(object sender , EventArgs args) =>
{
ListBox.ItemSource = args.Resullt;
Console.WriteLine("Hello");
}
When we talking about an expression lambda this is going to return some
type of value so in our example here we see we have a variable that's called
person and also of type person and then we have the cool and operator
in the middle and then we're taking the first name property of our parameter
and comparing it to the string "Sam" and this is obviously going to return a true or false
this is a shorthand version of writting out public school some method as a parameter
and then returning the result of the evalution of first name is equal to "Sam"
If we want to assign a method signature to this particular lambda expression
the method would be a method that takes one parameter of type person and returns a boolean
so it return a true / false value so that would be a signature that this lambda would match up to
are all expression lambdas predicates meaning they're all returning true/ false
參考自:
https://msdn.microsoft.com/zh-tw/library/0yw3tz5k.aspx
Getting Started with Lambda Expressions with Jeremy Clark
https://www.youtube.com/watch?v=xev-kNmz_a0
so let's go ahead and check that out so what we can do is we can create
a lambda expressions which is more comfortable with and since we don't have any
inputs that means open and closed paarenthesis with anothing in it
we have our lambda operator here the equals and more than symbol
and then we need to do something here
what is the task we want to complete well we could do a number of different things
but i'm simply going to create a very simple lambda expression
here and i'm going to say here that
Console.WriteLine task one is beginning and
then I will do some sort of Thread.sleep just to kind of pretend
that there's something else going on here in the background thread that sleep
if your underwears in the system dot threading namespace
in it is laeft over from much earlier versions of dot Net framework
but now it's really quite simple just takes in a number of milliseconds that
you want it to sit here and wait I'm gonna give it a thousand which basically
means I want you to sit here for a second and then I'm going to another
Console.WriteLine it's going to say task 1 has completed
So now we've created our task and we've given it an action what we wanted to perform and
so now let's see what happens Ctrl+F5
起始非同步工作
TPL 的核心類別是 Task
when you create a task in this way
Now there are other ways to create and I'll show you that in a few moments
but you create them in this way they don't start automatically.
you have to explicitly tell them to start using task.Start() instance method
要記得 Start 才會開始工作
語法: task.Start(); // 起始工作。
so now if we hit save and hit F5 you're going to see press any key to quit but also that
task one is beginning and task was completed so that was fairly quick
it was only a second in between I mean but if you see I had to sleep for 2 seconds
and hit F5 will see there a little bit longer task one is beginning
task one has completed
第一階段 練習code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Task_Parallel_Library
{
class Program
{
static void Main(string[] args)
{
var t1 = new Task(() =>{
Console.WriteLine("task 1 is beginning");
Thread.Sleep(1000); 1 second
Console.WriteLine("task 1 is has completed");
});
t1.Start();
Console.WriteLine("Press any key to quit");
Console.ReadKey();
}
}
}
//
Okay well it's not overly interesting
I'm not actually having this application do anything else while these tasks are executing
but where the task parallel library and tasks really start to shine is when you want to do
multiple things multiple operations or even multiple tasks at the same time.
So what I'm going to do now is I'm going to refactor this a little bit
because I want to share this code between multiple tasks
but I don't want just copy and paste this because
as you know from my previous lessons I can't stand duplication of my code
so what I'm going to do here is I'm going to create a new method
a static void method that's called "Do some very impportant work"
and I'm going to pass in a couple arguments
I'm going to pass in an it's going to an ID and I'm also going to pass in
and another end that's going to be sleep time so I can configure
this across multiple threads or multiple tasks
so I'm going to cut this logic out of here I'll paste in here and
I'm going to do a little bit of formatting in here nothing you haven't seen before this
is going to be the "id" and then we're going to set of hard-coding to 2,000
we're going to call this "sleepTime" and then we're going to format
this Console.WriteLine with the id as well.
And now in our lambda expression up here
we can get rid of these curly braces since we're really going to call one
method here and it;s going to do some very important work
in this task is the only job of this task and we're going to call the ID 1
and sleep time fifteen hundred milliseconds for a second and a half so
there we go save this week if we have five we should see
the same basic functionality
so nothing here to out of the ordinary
第二階段 練習code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Task_Parallel_Library
{
class Program
{
static void Main(string[] args)
{
var t1 = new Task(() => DosomeVeryImportantWork(1, 1500));
t1.Start();
Console.WriteLine("Press any key to quit");
Console.ReadKey();
}
static void DosomeVeryImportantWork(int id,int sleepTime)
{
Console.WriteLine("task {0} is beginning",id);
Thread.Sleep(1000);
Console.WriteLine("task {0} has completed",id);
}
}
}
//
So now what I would like to do is
I would like to show you how these things begin to execute in parallel
given the opportunity
we can try to copy these two lines I'm going to copy
and paste two moree of them here so now
I'm going to have the t2 and t3 to do some very important work
this is going to have an id of 2 and 3
and instead of waiting the same time this one's going to execute in three seconds
and the third one is going to execute in merely one second
you can see different output results !!
第三階段 練習code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Task_Parallel_Library
{
class Program
{
static void Main(string[] args)
{
var t1 = new Task(() => DosomeVeryImportantWork(1, 1500));
t1.Start();
var t2 = new Task(() => DosomeVeryImportantWork(2, 3000));
t2.Start();
var t3 = new Task(() => DosomeVeryImportantWork(3, 1000));
t3.Start();
Console.WriteLine("Press any key to quit");
Console.ReadKey();
}
static void DosomeVeryImportantWork(int id,int sleepTime)
{
Console.WriteLine("task {0} is beginning",id);
Thread.Sleep(1000);
Console.WriteLine("task {0} has completed",id);
}
}
}
//
學習參考用的 Youtube 影片
=====================================================================
Advanced C#: 14 Task Parallel Library
https://www.youtube.com/watch?v=gfkuD_eWM5Y
Getting Started with Lambda Expressions with Jeremy Clark
https://www.youtube.com/watch?v=xev-kNmz_a0
C# lambda expression as a function
https://www.youtube.com/watch?v=ooHyzbtr12w
學習引用資料的 來源 Blog
=====================================================================
C# Task 用法
http://www.wxzzz.com/683.html
Hacking C#’s Lambda Expressions Into Hash Rockets
https://joelholder.com/2013/07/19/hacking-cs-lambda-expressions-into-hash-rockets/
C# 學習筆記:多執行緒 (6) - TPL
http://huan-lin.blogspot.com/2013/06/csharp-notes-multithreading-6-tpl.html
[最多推薦]5天玩轉C#並行和多線程編程 —— 第三天 認識和使用Task(15/1539)
https://wefollownews.appspot.com/cittopnews201408_19/8019.html
C#線程篇---你所不知道的線程池
https://read01.com/EmEBDo.html
Thread Pooling in C#
http://www.c-sharpcorner.com/uploadfile/1d42da/threading-pooling-in-c-sharp/
Go Parallel with .NET 4.0 Parallel Extensions
http://udooz.net/blog/2009/08/parallel-programming-net-4-0-using-task/
新手淺談Task異步編程和Thread多線程編程
http://www.xlgps.com/article/215391.html
Processing streaming data with a thread pool
https://www.classes.cs.uchicago.edu/archive/2013/spring/12300-1/pa/pa2/
THREADS VS TASKS IN C#
http://jviaches.blogspot.tw/2015/07/threads-vs-tasks.html
英文片語 “Kind of / Sort of” 到底表示什麼意義?
http://english.ecominfozone.net/archives/4923
留言
張貼留言