〇、本文是我给自己的学习做的一个总结,不保证正确性,请读到本文的朋友谨慎参考,欢迎交流,谢谢。
明确一个问题:
=======================================================================
=====对于异步编程和多线程编程而言,异步是默认的,同步是需要想办法实现的。========
=======================================================================
一、同步编程和异步编程
参考:什么是线程同步和异步-最多言
首先编程中的同步异步说法的含义与实际中的含义是不同的,比如现在有两件事,听歌和洗衣服,下面以这两件事为例说明同步和异步
1.同步编程
同步就是指只有一条时间线,一个线程要等待上一个线程执行完之后才开始执行当前的线程。
也就是说:听歌,洗衣,洗衣,听歌。。。。,洗衣服的时候不听歌,听歌的时候不洗衣服。
2、异步编程
异步是指一个线程去执行,它的下一个线程不必等待它执行完就开始执行。
也就是说,边听歌边洗衣服
二、类Task、action、function、thread 和关键字 async/await
参考文章:[.NET]Thread与Task的区别 - 大杂草 - 博客园
在做一个有关于线程的程序代码时会用到这些类与关键字,
1、Class Thread
1.1 thread究竟是同步还是异步的?
Thread类被首先用于声明一个线程,需要明确的是用thread声明的这2个线程是异步的,这一点通过下面这个例子来证明:
namespace 线程实验
{
class Program
{
public static bool afin = false;
public static bool bfin = false;
static void Main(string[] args)
{
System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
Thread a1 = new Thread(metha);
Thread b1 = new Thread(methb);
st.Start();
a1.Start();
b1.Start();
while((afin==false)&&(bfin==false))
long time = st.ElapsedMilliseconds;
Console.WriteLine("time is:"+time.ToString());
Console.ReadKey();
}
public static void metha()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("111");
Console.WriteLine("22222");
Console.WriteLine("33333333");
Console.WriteLine("zzzzzzzzzzz");
Thread.Sleep(1000);
}
afin = true;
}
public static void methb()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("b");
Thread.Sleep(1000);
}
bfin = true;
}
}
}
需要明确的是用thread声明的这2个线程是异步的,也就是说他俩各自独立、同时运行,二者互不干涉,这一点可以从下面的运行结果上看出来,即在方法metha执行的过程中methb也在执行,
如2号圈中,显然在执行metha时,methb也在执行,而最后的二者时间相加也可以说明metha和methb是同时执行的,否则最后运行时间应该大于20000才对。
1.2、常见的使用thread类声明线程的方法
对于无参数方法而言:
方法1:Thread t = new Thread(method);
方法2:Thread t = new Thread(new Thread(method));
对于有参数方法而言:
Thread t = new Thread(new ParameterizedThreadStart(method));
以上语句声明了一个线程,但线程此时还只是声明完毕,还没有开始运行,运行线程的语句如下
对于无参数而言:t.Start();
对于有参数而言:t.Start(param);
现在线程开始执行了。
1.3、Class Thread的一些其他的知识点
2、Class Action 和 Class Function
2.1、这部分的概述
类action和类function都是委托,也就是delegate,更确切的说它们是两个用泛型标准写的两个delegate。
之所以要将这一部分放在这里,是由于线程是通过委托来实现的,回看一下之前声明线程的语句是不是有些像声明委托的语句?
委托声明:
public delegate void dele(string name);
public void method(string name);
dele d=method;
d("yyy");
线程声明:Thread t = new Thread(method);
而在task类中对action和function的使用更多。
2.2、类 Action
参考资料:Action
之前说过他使用泛型实现的delegate,看一下这个图,是微软官网上截到的,都是泛型的方法实现的,声明方法是这个:
public delegate void Action<in T>(T obj);
这是一个只有一个参数的action委托。
Action<......>,是专用于无返回值的函数,与之对应的是Task<Action>。
具体的使用方法为
public delegate void Action<in T>(T obj);
这是一个只有一个参数的action委托。
Action<string> messageTarget = Console.WriteLine;
意思是声明了一个需要一个参数的委托 messageTarget,这个委托所委托的是一个Console.WriteLine()方法。
messageTarget("Hello, World!");
意思是开始运行被代理的函数
和delegate对比一下是一样的。
public delegate void dele(string name);
dele d=Console.WriteLine;
d("yyy");
2.3、类 Function
参考资料:Func
这一部分和上面的差不多,区别在与Function是主要针对的是有返回值的函数的委托,看一下图:
如果只有一个参数那么最后一个就是返回值,如果有两个以上参数,那么最后的一个值就是返回值。
一个无参有返的委托的声明方法:
public delegate TResult Func<out TResult>();
3、类 Task
参考资料:百度安全验证
请高手们说说Task和Thread的区别_百度知道
面试必备:请问C#中Task和Thread有区别吗?如果有请简述区别_Run
task与thread的区别和使用讲解 https://www.jb51.net/article/250950.htm
3.1、Task的用途
task是异步编程的的核心,task在线程池的基础上进行了优化,提供了更多的API,Task类专门擅长于异步操作,于是就有了一个问题,thread也是异步编程,那么thread和Task有什么区别呢?为了回答这个问题应该梳理一下Task是如何来的。
3.2 、Task的来历
第一步,我们首先有了thread,这个类用以创造一些线程,用以实现异步编程
第二步,在现成的基础上,人们有发明了线程池 Threadpool, Threadpool其实就是thread的集合,具有很多优势,不过在任务多的时候全局队列会存在竞争而消耗资源。
线程池比之thread有许多优点:
thread默认为前台线程,主程序必须等线程跑完才会关闭,而threadpool相反。
但线程池也有如下缺点
- 不支持线程的取消,就像公园的摇摇车,坐上去后必须等这一圈跑完才能下来。
- 不支持线程执行的先后次序,这个有点像车站的出租车,坐上去后司机启动车的快慢乘客是无法控制的,因此当任务多的时候全局队列会存在竞争而消耗资源。
第三步,在上述线程池的基础上发展出了Task
task简单地看就是任务,那和thread有什么区别呢?
Task的背后的实现也是使用了线程池线程,但它的性能优于ThreadPoll,因为它使用的不是线程池的全局队列,而是使用的本地队列,使线程之间的资源竞争减少。
同时Task提供了丰富的API来管理线程、控制。
但是相对前面的两种耗内存,Task依赖于CPU对于多核的CPU性能远超前两者,单核的CPU三者的性能没什么差别。
于是我们可以回答3.1提出的问题,thread和Task有什么区别呢?
-
task是根据自己需要调用线程
-
thread就是个基本单位
-
简单地说,thread是单核多线程,task是多核多线程
-
Task是将多个操作封装成一个概念上原子操作。但这个操作由哪个Thread甚至多个Thread来处理处理你并不清楚。总之就是可以被正常完成。
-
Thread仅仅是一条线程,所有操作都是这个Thread一个人完成的。
-
Task较新,发布于.NET 4.5,能结合新的async/await代码模型写代码,它不止能创建新线程,还能使用线程池(默认)、单线程等方式编程,在UI编程领域,Task还能自动返回UI线程上下文,还提供了许多便利API以管理多个Task。
- Task默认使用线程池,也就是后台线程:当主线程结束时,你创建所有的tasks都会结束。
- Task.Run返回一个Task对象,可以使用它来监视其过程
- 在Task.Run之后,我们没有调用Start,因为该方法创建的是“热”任务(hot task)
- 可以通过task的构造函数创建“冷”任务(cold task),但开发中很少这么干
- 通过Task的Status属性来跟踪task的执行状态。
Task属于多核开发的封装。跟单线程工作的任务有很大的区别,甚至是本质上的区别。所以可比性不大。
3.3、Task的使用方法
Task类的使用与委托密不可分,就像delegate委托用泛型来实现时根据被委托的函数是否有返回值可以分为Action<...>和Func<...,Tresult>两种,Task类在使用时叶根据对应的委托是否有返回值分为两种:
Task类 | 对应void方法 | Task(Action) |
Task<TResult> | 有返回值的方法 | Task<TRsult>(Func<TResult>) |
Task taskA = Task.Run( () => Thread.Sleep(2000));
(1)Task类
这种一共有以下几种使用方法
using System;
using System.Threading;
using System.Threading.Tasks;
class Example
{
static void Main()
{
Action<object> action = (object obj) =>
{
Console.WriteLine("Task={0}, obj={1}, Thread={2}",
Task.CurrentId, obj,
Thread.CurrentThread.ManagedThreadId);
};
// t1这个任务是用声明一个Task类的实例的方法instantiated。
Task t1 = new Task(action, "alpha");
// t2这个任务实现用了Task.Factory.StartNew(action, "beta");这个语句。
Task t2 = Task.Factory.StartNew(action, "beta");
// Block the main thread to demonstrate that t2 is executing
t2.Wait();//这里代表着要等t2结束再往下运行
// 运行 t1
t1.Start();
Console.WriteLine("t1 has been launched. (Main Thread={0})",
Thread.CurrentThread.ManagedThreadId);
// Wait for the t1 task to finish.
t1.Wait();
// Construct a started task using Task.Run.用Task.Run这个语句构建了一个已经开始的任务t3;
String taskData = "delta";
Task t3 = Task.Run( () => {Console.WriteLine("Task={0}, obj={1}, Thread={2}",
Task.CurrentId, taskData,
Thread.CurrentThread.ManagedThreadId);
});
// Wait for the task t3 to finish.
t3.Wait();
// Construct an unstarted task
Task t4 = new Task(action, "gamma");
// Run it synchronously
t4.RunSynchronously();
// Although the task was run synchronously, it is a good practice
// to wait for it in the event exceptions were thrown by the task.
t4.Wait();
}
}
// The example displays output like the following:
// Task=1, obj=beta, Thread=3
// t1 has been launched. (Main Thread=1)
// Task=2, obj=alpha, Thread=4
// Task=3, obj=delta, Thread=3
// Task=4, obj=gamma, Thread=1
由上面的一段程序可以知道,使用task有大概这样三种方法
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)