威尼斯人线上娱乐

await与async的不易打开药格局,的那么些事情

31 3月 , 2019  

C#5.0生产了新语法,await与async,但相信大家依旧很少使用它们。关于await与async有无数小说讲解,但有没有如此一种感觉,你看完后,总感觉到这东西很不利,但用的时候,总是想不起来,只怕不清楚该怎么用。

C#中 Thread,Task,Async/Await,IAsyncResult 的那么些事儿!,

说起异步,Thread,Task,async/await,IAsyncResult
这几个事物自然是绕不开的,前几天就来挨家挨户聊聊他们

C#中 Thread,Task,Async/Await,IAsyncResult 的那个事情!,

说起异步,Thread,Task,async/await,IAsyncResult
那几个事物必定是绕不开的,明天就来挨家挨户聊聊他们

 

1.线程(Thread)

 

十二线程的意思在于1个应用程序中,有三个实施部分能够同时实施;对于相比耗费时间的操作(例如io,数据库操作),或然等待响应(如WCF通讯)的操作,能够独立开启后台线程来进行,那样主线程就不会阻塞,能够三番五次往下进行;等到后台线程执行完成,再公告主线程,然后做出相应操作!

 

在C#中开启新线程比较简单

 

static void Main(string[] args)
{
    Console.WriteLine("主线程开始");
    //IsBackground=true,将其设置为后台线程
    Thread t = new Thread(Run) { IsBackground = true };
    t.Start();
   Console.WriteLine("主线程在做其他的事!");
    //主线程结束,后台线程会自动结束,不管有没有执行完成
    //Thread.Sleep(300);
    Thread.Sleep(1500);
    Console.WriteLine("主线程结束");
}
static void Run()
{
    Thread.Sleep(700);
    Console.WriteLine("这是后台线程调用");
}

 

实践结果如下图

 

威尼斯人线上娱乐 1

 

能够见到在起步后台线程之后,主线程继续往下执行了,并从未等到后台线程执行完事后。

 

说起异步,Thread,Task,async/await,IAsyncResult
这么些事物自然是绕不开的,前几天就来挨家挨户聊聊他们

何以吗?小编以为大家的await与async的打开药格局不得法。

1.线程(Thread)

二十多线程的意义在于一个应用程序中,有七个执行部分能够同时实施;对于相比耗费时间的操作(例如io,数据库操作),或然等待响应(如WCF通信)的操作,能够单独开启后台线程来实施,那样主线程就不会卡住,可以继续往下举办;等到后台线程执行完结,再布告主线程,然后做出相应操作!

在C#中拉开新线程比较不难

static void Main(string[] args)
{
    Console.WriteLine("主线程开始");
    //IsBackground=true,将其设置为后台线程
    Thread t = new Thread(Run) { IsBackground = true };
    t.Start();
   Console.WriteLine("主线程在做其他的事!");
    //主线程结束,后台线程会自动结束,不管有没有执行完成
    //Thread.Sleep(300);
    Thread.Sleep(1500);
    Console.WriteLine("主线程结束");
}
static void Run()
{
    Thread.Sleep(700);
    Console.WriteLine("这是后台线程调用");
}

 执行结果如下图,

威尼斯人线上娱乐 2

能够看到在起步后台线程之后,主线程继续往下执行了,并从未等到后台线程执行完事后。

1.1 线程池

 

试想一下,如若有大气的天职急需处理,例如网站后台对于HTTP请求的拍卖,那是或不是要对每3个请求创立1个后台线程呢?显著不合适,那会占据多量内部存款和储蓄器,而且往往地成立的进度也会严重影响速度,那怎么做呢?

 

线程池正是为着消除这一标题,把创造的线程存起来,形成二个线程池(里面有两个线程),当要处理职责时,若线程池中有空余线程(前三个义务履行到位后,线程不会被回收,会被设置为空闲状态),则平昔调用线程池中的线程执行(例asp.net处理体制中的Application对象),使用事例:

 

for (int i = 0; i < 10; i++)
{
    ThreadPool.QueueUserWorkItem(m =>
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
    });
}
Console.Read();

 

运维结果:

 

威尼斯人线上娱乐 3

 

能够看看,即使实施了13遍,但并不曾成立13个线程。

 

1.2 信号量(Semaphore)

 

Semaphore负责协调线程,可以限制对某一能源访问的线程数量,那里对SemaphoreSlim类的用法做贰个大约的例子:

 

static SemaphoreSlim semLim = new SemaphoreSlim(3); //3表示最多只能有三个线程同时访问
static void Main(string[] args)
{
    for (int i = 0; i < 10; i++)
    {
        new Thread(SemaphoreTest).Start();
    }
    Console.Read();
}
static void SemaphoreTest()
{
    semLim.Wait();
    Console.WriteLine("线程" + Thread.CurrentThread.ManagedThreadId.ToString() + "开始执行");
    Thread.Sleep(2000);
    Console.WriteLine("线程" + Thread.CurrentThread.ManagedThreadId.ToString() + "执行完毕");
    semLim.Release();
}

 

实行结果如下:

 

威尼斯人线上娱乐 4

 

威尼斯人线上娱乐 5

 

能够看来,刚初叶唯有多少个线程在推行,当贰个线程执行实现并释放之后,才会有新的线程来举行办法!

 

除开SemaphoreSlim类,还足以选择塞马phore类,感觉越是灵敏,感兴趣的话能够搜一下,这里就不做示范了!

 

 

 正确的打开药格局

1.1 线程池

试想一下,假如有雅量的天职急需处理,例如网站后台对于HTTP请求的拍卖,那是否要对每三个请求成立三个后台线程呢?鲜明不合适,那会占据大批量内部存款和储蓄器,而且往往地创造的进程也会严重影响速度,那如何是好呢?线程池便是为了化解这一标题,把创造的线程存起来,形成2个线程池(里面有多少个线程),当要处理职责时,若线程池中有空闲线程(前三个职责执行到位后,线程不会被回收,会被安装为空闲状态),则直接调用线程池中的线程执行(例asp.net处理机制中的Application对象),

选择事例:

for (int i = 0; i < 10; i++)
{
    ThreadPool.QueueUserWorkItem(m =>
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
    });
}
Console.Read();

运营结果:

威尼斯人线上娱乐 6

能够观望,固然实施了拾四遍,但并不曾开创11个线程。

2.Task

 

Task是.NET4.0出席的,跟线程池ThreadPool的效劳看似,用Task开启新职责时,会从线程池中调用线程,而Thread每一遍实例化都会成立二个新的线程。

 

Console.WriteLine("主线程启动");
//Task.Run启动一个线程
//Task启动的是后台线程,要在主线程中等待后台线程执行完毕,可以调用Wait方法
//Task task = Task.Factory.StartNew(() => { Thread.Sleep(1500); Console.WriteLine("task启动"); });
Task task = Task.Run(() => { 
    Thread.Sleep(1500);
    Console.WriteLine("task启动");
});
Thread.Sleep(300);
task.Wait();
Console.WriteLine("主线程结束");

 

履行结果如下:

 

威尼斯人线上娱乐 7

 

开启新任务的格局:Task.Run()或许Task.Factory.StartNew(),开启的是后台线程要在主线程中等待后台线程执行完成,能够选取Wait方法(会以共同的办法来施行)。不用Wait则会以异步的点子来实施。

 

正如一下Task和Thread:

 

static void Main(string[] args)
{
    for (int i = 0; i < 5; i++)
    {
        new Thread(Run1).Start();
    }
    for (int i = 0; i < 5; i++)
    {
        Task.Run(() => { Run2(); });
    }
}
static void Run1()
{
    Console.WriteLine("Thread Id =" + Thread.CurrentThread.ManagedThreadId);
}
static void Run2()
{
    Console.WriteLine("Task调用的Thread Id =" + Thread.CurrentThread.ManagedThreadId);
}

 

推行结果:

 

威尼斯人线上娱乐 8

 

能够看出来,直接用Thread会开启多少个线程,用Task(用了线程池)开启了2个!

 

1.线程(Thread)

 

 1.2 信号量(Semaphore)

 Semaphore负责协调线程,能够限制对某一能源访问的线程数量

 那里对SemaphoreSlim类的用法做1个简便的事例:

static SemaphoreSlim semLim = new SemaphoreSlim(3); //3表示最多只能有三个线程同时访问
static void Main(string[] args)
{
    for (int i = 0; i < 10; i++)
    {
        new Thread(SemaphoreTest).Start();
    }
    Console.Read();
}
static void SemaphoreTest()
{
    semLim.Wait();
    Console.WriteLine("线程" + Thread.CurrentThread.ManagedThreadId.ToString() + "开始执行");
    Thread.Sleep(2000);
    Console.WriteLine("线程" + Thread.CurrentThread.ManagedThreadId.ToString() + "执行完毕");
    semLim.Release();
}

进行结果如下:

威尼斯人线上娱乐 9威尼斯人线上娱乐 10

能够看到,刚初步唯有三个线程在进行,当多个线程执行实现并释放之后,才会有新的线程来推行格局!

除开SemaphoreSlim类,还足以选择Semaphore类,感觉越是灵活,感兴趣的话能够搜一下,那里就不做示范了!

2.1 Task<TResult>

 

Task<TResult>正是有再次来到值的Task,TResult就是再次来到值类型。

 

Console.WriteLine("主线程开始");
//返回值类型为string
Task<string> task = Task<string>.Run(() => {
    Thread.Sleep(2000); 
    return Thread.CurrentThread.ManagedThreadId.ToString(); 
});
//会等到task执行完毕才会输出;
Console.WriteLine(task.Result);
Console.WriteLine("主线程结束");

 

运维结果:

 

威尼斯人线上娱乐 11

 

经过task.Result能够取到再次来到值,若取值的时候,后台线程还没执行完,则会等待其实施完结!

 

简单的说提一下:

 

Task职务能够因而CancellationTokenSource类来撤除,感觉用得不多,用法比较简单,感兴趣的话能够搜一下!

 

 

先是看下使用约束。

2.Task

Task是.NET4.0投入的,跟线程池ThreadPool的功力看似,用Task开启新任务时,会从线程池中调用线程,而Thread每一回实例化都会成立1个新的线程。

Console.WriteLine("主线程启动");
//Task.Run启动一个线程
//Task启动的是后台线程,要在主线程中等待后台线程执行完毕,可以调用Wait方法
//Task task = Task.Factory.StartNew(() => { Thread.Sleep(1500); Console.WriteLine("task启动"); });
Task task = Task.Run(() => { 
    Thread.Sleep(1500);
    Console.WriteLine("task启动");
});
Thread.Sleep(300);
task.Wait();
Console.WriteLine("主线程结束");

履行结果如下:

威尼斯人线上娱乐 12

打开新职分的法门:Task.Run()只怕Task.Factory.StartNew(),开启的是后台线程

要在主线程中等待后台线程执行达成,能够接纳Wait方法(会以共同的方法来执行)。不用Wait则会以异步的法子来施行。

正如一下Task和Thread:

static void Main(string[] args)
{
    for (int i = 0; i < 5; i++)
    {
        new Thread(Run1).Start();
    }
    for (int i = 0; i < 5; i++)
    {
        Task.Run(() => { Run2(); });
    }
}
static void Run1()
{
    Console.WriteLine("Thread Id =" + Thread.CurrentThread.ManagedThreadId);
}
static void Run2()
{
    Console.WriteLine("Task调用的Thread Id =" + Thread.CurrentThread.ManagedThreadId);
}

履行结果:

威尼斯人线上娱乐 13

能够看出来,间接用Thread会开启6个线程,用Task(用了线程池)开启了一个!

3. async/await

 

async/await是C#5.0中推出的,先上用法:

 

static void Main(string[] args)
{
    Console.WriteLine("-------主线程启动-------");
    Task<int> task = GetStrLengthAsync();
    Console.WriteLine("主线程继续执行");
    Console.WriteLine("Task返回的值" + task.Result);
    Console.WriteLine("-------主线程结束-------");
}
static async Task<int> GetStrLengthAsync()
{
    Console.WriteLine("GetStrLengthAsync方法开始执行");
    //此处返回的<string>中的字符串类型,而不是Task<string>
    string str = await GetString();
    Console.WriteLine("GetStrLengthAsync方法执行结束");
    return str.Length;
}
static Task<string> GetString()
{
   //Console.WriteLine("GetString方法开始执行")
    return Task<string>.Run(() =>
    {
        Thread.Sleep(2000);
        return "GetString的返回值";
    });
}

 

async用来修饰方法,申明那几个点子是异步的,评释的法门的回来类型必须为:void,Task或Task<TResult>。

 

await必须用来修饰Task或Task<TResult>,而且不得不出现在已经用async关键字修饰的异步方法中。常常情形下,async/await成对出现才有含义,看看运营结果:

 

威尼斯人线上娱乐 14

 

能够看出来,main函数调用GetStrLengthAsync方法后,在await从前,都以一路施行的,直到遇见await关键字,main函数才回来继续执行。

 

那么是或不是是在碰到await关键字的时候程序自动开启了二个后台线程去实施GetString方法呢?

 

前些天把GetString方法中的那行注释加上,运营的结果是:

 

威尼斯人线上娱乐 15

 

大家能够看看,在遇见await关键字后,没有继续执行GetStrLengthAsync方法后边的操作,也尚未马上反回到main函数中,而是举行了GetString的率先行,以此能够看清await那里并从未开启新的线程去实践GetString方法,而是以共同的主意让GetString方法执行,等到执行到GetString方法中的Task<string>.Run()的时候才由Task开启了后台线程!

 

这就是说await的功能是怎样吧?

 

能够从字面上精通,上边提到task.wait能够让主线程等待后台线程执行完成,await和wait类似,同样是等待,等待Task<string>.Run()开头的后台线程执行完成,差别的是await不会阻塞主线程,只会让GetStrLengthAsync方法暂停实施。

 

那么await是怎么形成的啊?有没有打开新线程去等待?

 

威尼斯人线上娱乐 16

 

只有八个线程(主线程和Task开启的线程)!至于如何是好到的(作者也不知道……>_<),大家有趣味的话研商下呢!

 

三十二线程的意思在于七个应用程序中,有多个执行部分能够同时执行;对于比较耗费时间的操作(例如io,数据库操作),或然等待响应(如WCF通讯)的操作,能够独立开启后台线程来举行,那样主线程就不会阻塞,能够连续往下执行;等到后台线程执行完成,再布告主线程,然后做出相应操作!

① 、await 只幸好标记了async的函数内采取。

2.1 Task<TResult>

Task<TResult>正是有重回值的Task,TResult正是回去值类型。

Console.WriteLine("主线程开始");
//返回值类型为string
Task<string> task = Task<string>.Run(() => {
    Thread.Sleep(2000); 
    return Thread.CurrentThread.ManagedThreadId.ToString(); 
});
//会等到task执行完毕才会输出;
Console.WriteLine(task.Result);
Console.WriteLine("主线程结束");

运作结果:

威尼斯人线上娱乐 17

透过task.Result能够取到重回值,若取值的时候,后台线程还没实施完,则会等待其执行达成!

粗略提一下:

Task职分能够通过CancellationTokenSource类来撤销,感觉用得不多,用法比较简单,感兴趣的话能够搜一下!

4.IAsyncResult

 

IAsyncResult自.NET1.1起就有了,包涵可异步操作的方法的类要求完毕它,Task类就贯彻了该接口

 

 

威尼斯人线上娱乐 18

 

在不依赖Task的境况下怎么落到实处异步呢?

 

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("主程序开始--------------------");
        int threadId;
        AsyncDemo ad = new AsyncDemo();
        AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
 
        IAsyncResult result = caller.BeginInvoke(3000,out threadId, null, null);
        Thread.Sleep(0);
        Console.WriteLine("主线程线程 {0} 正在运行.",Thread.CurrentThread.ManagedThreadId)
        //会阻塞线程,直到后台线程执行完毕之后,才会往下执行
        result.AsyncWaitHandle.WaitOne();
        Console.WriteLine("主程序在做一些事情!!!");
        //获取异步执行的结果
        string returnValue = caller.EndInvoke(out threadId, result);
        //释放资源
        result.AsyncWaitHandle.Close();
        Console.WriteLine("主程序结束--------------------");
        Console.Read();
    }
}
public class AsyncDemo
{
    //供后台线程执行的方法
    public string TestMethod(int callDuration, out int threadId)
    {
        Console.WriteLine("测试方法开始执行.");
        Thread.Sleep(callDuration);
        threadId = Thread.CurrentThread.ManagedThreadId;
        return String.Format("测试方法执行的时间 {0}.", callDuration.ToString());
    }
}
public delegate string AsyncMethodCaller(int callDuration, out int threadId);

 

关键步骤正是革命字体的部分,运营结果:

 

威尼斯人线上娱乐 19

 

和Task的用法差别不是相当的大!result.AsyncWaitHandle.WaitOne()就接近Task的Wait。

 

5.Parallel

 

末尾说一下在循环中打开八线程的粗略方法:

 

Stopwatch watch1 = new Stopwatch();
watch1.Start();
for (int i = 1; i <= 10; i++)
{
    Console.Write(i + ",");
    Thread.Sleep(1000);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed);
Stopwatch watch2 = new Stopwatch();
watch2.Start();
//会调用线程池中的线程
Parallel.For(1, 11, i =>
{
    Console.WriteLine(i + ",线程ID:" + Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(1000);
});
watch2.Stop();
Console.WriteLine(watch2.Elapsed);

 

运作结果:

 

威尼斯人线上娱乐 20

 

循环List<T>:

 

List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 6, 7, 8, 9 };
Parallel.ForEach<int>(list, n =>
{
    Console.WriteLine(n);
    Thread.Sleep(1000);
});

 

执行Action[]数组里面包车型地铁法门:

 

Action[] actions = new Action[] { 
   new Action(()=>{
       Console.WriteLine("方法1");
   }),
    new Action(()=>{
       Console.WriteLine("方法2");
   })
};
Parallel.Invoke(actions);

 

贰 、await 等待的函数必须标记async。

 3. async/await

async/await是C#5.0中推出的,先上用法:

static void Main(string[] args)
{
    Console.WriteLine("-------主线程启动-------");
    Task<int> task = GetStrLengthAsync();
    Console.WriteLine("主线程继续执行");
    Console.WriteLine("Task返回的值" + task.Result);
    Console.WriteLine("-------主线程结束-------");
}

static async Task<int> GetStrLengthAsync()
{
    Console.WriteLine("GetStrLengthAsync方法开始执行");
    //此处返回的<string>中的字符串类型,而不是Task<string>
    string str = await GetString();
    Console.WriteLine("GetStrLengthAsync方法执行结束");
    return str.Length;
}

static Task<string> GetString()
{
   //Console.WriteLine("GetString方法开始执行")
    return Task<string>.Run(() =>
    {
        Thread.Sleep(2000);
        return "GetString的返回值";
    });
}

async用来修饰方法,申明那一个点子是异步的,申明的点子的归来类型必须为:void,Task或Task<TResult>。

await必须用来修饰Task或Task<TResult>,而且只可以出现在已经用async关键字修饰的异步方法中。经常情形下,async/await成对出现才有含义,

看望运维结果:

威尼斯人线上娱乐 21

能够看出来,main函数调用GetStrLengthAsync方法后,在await以前,都以二头实施的,直到遇见await关键字,main函数才回去继续执行。

这便是说是不是是在蒙受await关键字的时候程序自动开启了三个后台线程去实施GetString方法吧?

近年来把GetString方法中的那行注释加上,运营的结果是:

威尼斯人线上娱乐 22

大家可以观看,在遇见await关键字后,没有继续执行GetStrLengthAsync方法前面包车型大巴操作,也平素不即时反回到main函数中,而是举办了GetString的率先行,以此能够看清await那里并从未打开新的线程去履行GetString方法,而是以协同的主意让GetString方法执行,等到执行到GetString方法中的Task<string>.Run()的时候才由Task开启了后台线程!

那么await的功能是怎么啊?

能够从字面上驾驭,上面提到task.wait能够让主线程等待后台线程执行完成,await和wait类似,同样是等待,等待Task<string>.Run()初叶的后台线程执行落成,不一致的是await不会阻塞主线程,只会让GetStrLengthAsync方法暂停实施。

那就是说await是怎么形成的啊?有没有打开新线程去等待?

威尼斯人线上娱乐 23

唯有七个线程(主线程和Task开启的线程)!至于怎么完结的(小编也不知道……>_<),我们有趣味的话研讨下呢!

 

在C#中开启新线程相比简单

有没有痛感那是个循环?没错,这正是个巡回。这也正是怎么大家有个别用他们的原由。那么些轮回很看不惯,那么怎么消除这一个轮回呢?

4.IAsyncResult

IAsyncResult自.NET1.1起就有了,包含可异步操作的方式的类必要达成它,Task类就完成了该接口

威尼斯人线上娱乐 24

在不借助于Task的情状下怎么落实异步呢?

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("主程序开始--------------------");
        int threadId;
        AsyncDemo ad = new AsyncDemo();
        AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

        IAsyncResult result = caller.BeginInvoke(3000,out threadId, null, null);
        Thread.Sleep(0);
        Console.WriteLine("主线程线程 {0} 正在运行.",Thread.CurrentThread.ManagedThreadId)
        //会阻塞线程,直到后台线程执行完毕之后,才会往下执行
        result.AsyncWaitHandle.WaitOne();
        Console.WriteLine("主程序在做一些事情!!!");
        //获取异步执行的结果
        string returnValue = caller.EndInvoke(out threadId, result);
        //释放资源
        result.AsyncWaitHandle.Close();
        Console.WriteLine("主程序结束--------------------");
        Console.Read();
    }
}
public class AsyncDemo
{
    //供后台线程执行的方法
    public string TestMethod(int callDuration, out int threadId)
    {
        Console.WriteLine("测试方法开始执行.");
        Thread.Sleep(callDuration);
        threadId = Thread.CurrentThread.ManagedThreadId;
        return String.Format("测试方法执行的时间 {0}.", callDuration.ToString());
    }
}
public delegate string AsyncMethodCaller(int callDuration, out int threadId);

关键步骤就是乙酉革命字体的有的,运转结果:

威尼斯人线上娱乐 25

和Task的用法差别不是一点都不小!result.AsyncWaitHandle.WaitOne()就类似Task的Wait。

6.异步的回调

 

为了简洁(偷懒),文中全部Task<TResult>的再次回到值都以一向用task.result获取,那样一旦后台职务没有执行达成的话,主线程会等待其实践落成。那样的话就和协助举行一样了,一般情况下不会那样用。不难演示一下Task回调函数的应用:

await与async的不易打开药格局,的那么些事情。 

Console.WriteLine("主线程开始");
Task<string> task = Task<string>.Run(() => {
    Thread.Sleep(2000); 
    return Thread.CurrentThread.ManagedThreadId.ToString(); 
});
//会等到任务执行完之后执行
task.GetAwaiter().OnCompleted(() =>
{
    Console.WriteLine(task.Result);
});
Console.WriteLine("主线程结束");
Console.Read();

 

实施结果:

 

威尼斯人线上娱乐 26

 

OnCompleted中的代码会在职分履行到位之后执行!

 

其余task.ContinueWith()也是1个第贰的措施:

 

Console.WriteLine("主线程开始");
Task<string> task = Task<string>.Run(() => {
    Thread.Sleep(2000); 
    return Thread.CurrentThread.ManagedThreadId.ToString(); 
});
task.GetAwaiter().OnCompleted(() =>
{
    Console.WriteLine(task.Result);
});
task.ContinueWith(m=>{Console.WriteLine("第一个任务结束啦!我是第二个任务");});
Console.WriteLine("主线程结束");
Console.Read();

 

实施结果:

 

威尼斯人线上娱乐 27

 

ContinueWith()方法能够让该后台线程继续执行新的职责。

 

Task的应用依旧相比较灵活的,我们能够探究下,好了,以上正是全体内容了,篇幅和力量都不难,希望对我们有用!

Thread,Task,Async/Await,IAsyncResult
的这个事情!, 说起异步,Thread,Task,async/await,IAsyncResult
那些事物一定是绕不开的,前几日就来依次…

 

【一点也不细略,await等待的是线程,不是函数。】

 5.Parallel

说到底说一下在循环中打开四线程的简易方法:

Stopwatch watch1 = new Stopwatch();
watch1.Start();
for (int i = 1; i <= 10; i++)
{
    Console.Write(i + ",");
    Thread.Sleep(1000);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed);

Stopwatch watch2 = new Stopwatch();
watch2.Start();

//会调用线程池中的线程
Parallel.For(1, 11, i =>
{
    Console.WriteLine(i + ",线程ID:" + Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(1000);
});
watch2.Stop();
Console.WriteLine(watch2.Elapsed);

运作结果:

威尼斯人线上娱乐 28

循环List<T>:

List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 6, 7, 8, 9 };
Parallel.ForEach<int>(list, n =>
{
    Console.WriteLine(n);
    Thread.Sleep(1000);
});

执行Action[]数组里面包车型客车法子:

Action[] actions = new Action[] { 
   new Action(()=>{
       Console.WriteLine("方法1");
   }),
    new Action(()=>{
       Console.WriteLine("方法2");
   })
};
Parallel.Invoke(actions);

static void Main(string[] args)

{

    Console.WriteLine(“主线程开头”);

    //IsBackground=true,将其设置为后台线程

    Thread t = new Thread(Run) { IsBackground = true };

    t.Start();

   Console.WriteLine(“主线程在做任何的事!”);

    //主线程截止,后台线程会自行终止,不管有没有实施到位

    //Thread.Sleep(300);

    Thread.Sleep(1500);

    Console.WriteLine(“主线程甘休”);

}

static void Run()

{

    Thread.Sleep(700);

    Console.WriteLine(“那是后台线程调用”);

}

不知底吧?没关系,接着看下来。

6.异步的回调

为了简洁(偷懒),文中全部Task<TResult>的重临值皆以直接用task.result获取,那样要是后台职务没有实施实现的话,主线程会等待其实施完结。那样的话就和共同一样了,一般景观下不会如此用。不难演示一下Task回调函数的利用:

Console.WriteLine("主线程开始");
Task<string> task = Task<string>.Run(() => {
    Thread.Sleep(2000); 
    return Thread.CurrentThread.ManagedThreadId.ToString(); 
});
//会等到任务执行完之后执行
task.GetAwaiter().OnCompleted(() =>
{
    Console.WriteLine(task.Result);
});
Console.WriteLine("主线程结束");
Console.Read();

进行结果:

威尼斯人线上娱乐 29

OnCompleted中的代码会在任务执行到位之后执行!

除此以外task.ContinueWith()也是2个至关心注重要的法门:

Console.WriteLine("主线程开始");
Task<string> task = Task<string>.Run(() => {
    Thread.Sleep(2000); 
    return Thread.CurrentThread.ManagedThreadId.ToString(); 
});

task.GetAwaiter().OnCompleted(() =>
{
    Console.WriteLine(task.Result);
});
task.ContinueWith(m=>{Console.WriteLine("第一个任务结束啦!我是第二个任务");});
Console.WriteLine("主线程结束");
Console.Read();

进行结果:

威尼斯人线上娱乐 30

孔蒂nueWith()方法能够让该后台线程继续执行新的天职。

Task的利用也许比较灵敏的,大家能够商讨下,好了,以上正是全体内容了,篇幅和能力都有数,希望对大家有用!

 

Thread,Task,Async/Await,IAsyncResult
的那多少个事儿!, 说起异步,Thread,Task,async/await,IAsyncResult
那些事物自然是绕不开的,前日就来依次…

 

上边从头来讲解,首先看那样一组相比

实施结果如下图

public static int NoAsyncTest()
{
   return 1;
}
public static async Task<int> AsyncTest()
{ 
  return 1;
}

 

 async Task<int>等于int

威尼斯人线上娱乐 31

那代表我们在例行调用那五个函数时,他们是一律的。那么用async
Task<int>来修饰int指标是怎么着呢?

 

目标是为了让那个法子这么被调用 await
AsyncTest(),但直接那样调用,并不会开启线程,这那样辛勤的修饰是否就没怎么意义了吗。

能够观察在开发银行后台线程之后,主线程继续往下执行了,并不曾等到后台线程执行完事后。

理所当然不是,那怎么时候会让 await AsyncTest()有意义呢?

 

咱俩跟着往下看,修改AsyncTest如下。然后,此时再调用await
AsyncTest(),你会神奇的发现,依旧没有卵用。。。

1.1 线程池

 

试想一下,假若有雅量的职务急需处理,例如网站后台对于HTTP请求的拍卖,那是或不是要对每一个伸手成立三个后台线程呢?显著不合适,那会占有大量内部存款和储蓄器,而且数1七次地创造的进程也会严重影响进程,那怎么办吧?

 

线程池正是为了化解这一题材,把创造的线程存起来,形成1个线程池(里面有多少个线程),当要拍卖职责时,若线程池中有空闲线程(前3个任务执行到位后,线程不会被回收,会棉被服装置为空闲状态),则平昔调用线程池中的线程执行(例asp.net处理机制中的Application对象),使用事例:

 

for (int i = 0; i < 10; i++)

{

    ThreadPool.QueueUserWorkItem(m =>

    {

       
Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());

    });

}

Console.Read();

 

运营结果:

 

威尼斯人线上娱乐 32

 

能够看到,就算举办了十二遍,但并没有开创11个线程。

 

1.2 信号量(Semaphore)

 

Semaphore负责协调线程,能够限制对某一财富访问的线程数量,那里对SemaphoreSlim类的用法做2个粗略的事例:

 

static SemaphoreSlim semLim = new SemaphoreSlim(3);
//3表示最八只可以有三个线程同时做客

static void Main(string[] args)

{

    for (int i = 0; i < 10; i++)

    {

        new Thread(SemaphoreTest).Start();

    }

    Console.Read();

}

static void SemaphoreTest()

{

    semLim.Wait();

    Console.WriteLine(“线程” +
Thread.CurrentThread.ManagedThreadId.ToString() + “先导施行”);

    Thread.Sleep(2000);

    Console.WriteLine(“线程” +
Thread.CurrentThread.ManagedThreadId.ToString() + “执行完成”);

    semLim.Release();

}

 

履行结果如下:

 

威尼斯人线上娱乐 33

 

威尼斯人线上娱乐 34

 

能够看看,刚开头唯有三个线程在实践,当3个线程执行完结并释放之后,才会有新的线程来实施措施!

 

除了那几个之外SemaphoreSlim类,还是能够利用Semaphore类,感觉越是灵敏,感兴趣的话能够搜一下,这里就不做示范了!

 

Excute方法平常履行,而AsyncTest内运行的线程,本身执行自身的。

2.Task

 

Task是.NET4.0进入的,跟线程池ThreadPool的职能看似,用Task开启新任务时,会从线程池中调用线程,而Thread每一次实例化都会创立三个新的线程。

 

Console.WriteLine(“主线程运营”);

//Task.Run运转多个线程

//Task运营的是后台线程,要在主线程中等待后台线程执行完结,能够调用Wait方法

//Task task = Task.Factory.StartNew(() => { Thread.Sleep(1500);
Console.WriteLine(“task启动”); });

Task task = Task.Run(() => { 

    Thread.Sleep(1500);

    Console.WriteLine(“task启动”);

});

Thread.Sleep(300);

task.Wait();

Console.WriteLine(“主线程甘休”);

 

进行结果如下:

 

威尼斯人线上娱乐 35

 

敞开新职分的法门:Task.Run()或许Task.Factory.StartNew(),开启的是后台线程要在主线程中等待后台线程执行完毕,能够应用Wait方法(会以协同的艺术来实施)。不用Wait则会以异步的不二法门来进行。

 

正如一下Task和Thread:

 

static void Main(string[] args)

{

    for (int i = 0; i < 5; i++)

    {

        new Thread(Run1).Start();

    }

    for (int i = 0; i < 5; i++)

    {

        Task.Run(() => { Run2(); });

    }

}

static void Run1()

{

    Console.WriteLine(“Thread Id =” +
Thread.CurrentThread.ManagedThreadId);

}

static void Run2()

{

    Console.WriteLine(“Task调用的Thread Id =” +
Thread.CurrentThread.ManagedThreadId);

}

 

实践结果:

 

威尼斯人线上娱乐 36

 

能够看出来,直接用Thread会开启5个线程,用Task(用了线程池)开启了3个!

 

public static async void Excute()
 {
       Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 开始 Excute " + DateTime.Now);
       await AsyncTest();
       Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 结束 Excute " + DateTime.Now);
 }

 public static async Task<int> AsyncTest()
 {
        Task.Run(() =>
            {
                Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run1 " + DateTime.Now);
                Thread.Sleep(1000);
            });
            return 1;
 }

2.1 Task<TResult>

 

Task<TResult>就是有再次回到值的Task,TResult正是回去值类型。

 

Console.WriteLine(“主线程初叶”);

//再次来到值类型为string

Task<string> task = Task<string>.Run(() => {

    Thread.Sleep(2000); 

    return Thread.CurrentThread.ManagedThreadId.ToString(); 

});

//会等到task执行达成才会输出;

Console.WriteLine(task.Result);

Console.WriteLine(“主线程甘休”);

 

运维结果:

 

威尼斯人线上娱乐 37

 

透过task.Result能够取到再次来到值,若取值的时候,后台线程还没实施完,则会等待其履行完结!

 

简单来讲提一下:

 

Task任务能够经过CancellationTokenSource类来裁撤,感觉用得不多,用法相比较不难,感兴趣的话能够搜一下!

 

威尼斯人线上娱乐 38

3. async/await

 

async/await是C#5.0中推出的,先上用法:

 

static void Main(string[] args)

{

    Console.WriteLine(“——-主线程运转——-“);

    Task<int> task = GetStrLengthAsync();

    Console.WriteLine(“主线程继续执行”);

    Console.WriteLine(“Task重返的值” + task.Result);

    Console.WriteLine(“——-主线程截止——-“);

}

static async Task<int> GetStrLengthAsync()

{

    Console.WriteLine(“GetStrLengthAsync方法初始实践”);

    //此处再次回到的<string>中的字符串类型,而不是Task<string>

    string str = await GetString();

    Console.WriteLine(“GetStrLengthAsync方法执行完成”);

    return str.Length;

}

static Task<string> GetString()

{

   //Console.WriteLine(“GetString方法开端推行”)

    return Task<string>.Run(() =>

    {

        Thread.Sleep(2000);

        return “GetString的重返值”;

    });

}

 

async用来修饰方法,注解这几个格局是异步的,注明的法门的回到类型必须为:void,Task或Task<TResult>。

 

await必须用来修饰Task或Task<TResult>,而且只可以出现在早就用async关键字修饰的异步方法中。常常状态下,async/await成对现身才有意义,看看运转结果:

 

威尼斯人线上娱乐 39

 

能够看出来,main函数调用GetStrLengthAsync方法后,在await以前,都以手拉手执行的,直到碰着await关键字,main函数才回去继续执行。

 

那就是说是或不是是在碰着await关键字的时候程序自动开启了四个后台线程去实施GetString方法吗?

 

前些天把GetString方法中的那行注释加上,运营的结果是:

 

威尼斯人线上娱乐 40

 

世家能够观望,在境遇await关键字后,没有继续执行GetStrLengthAsync方法后边的操作,也一直不马上反回到main函数中,而是举办了GetString的首先行,以此能够判明await那里并不曾拉开新的线程去履行GetString方法,而是以协同的法门让GetString方法执行,等到执行到GetString方法中的Task<string>.Run()的时候才由Task开启了后台线程!

 

那么await的机能是什么啊?

 

能够从字面上精通,下边提到task.wait能够让主线程等待后台线程执行达成,await和wait类似,同样是等待,等待Task<string>.Run()开头的后台线程执行完成,不一样的是await不会堵塞主线程,只会让GetStrLengthAsync方法暂停实施。

 

那正是说await是怎么办到的啊?有没有打开新线程去等待?

 

威尼斯人线上娱乐 41

 

唯有三个线程(主线程和Task开启的线程)!至于怎么形成的(小编也不知道……>_<),我们有趣味的话研究下吧!

 

别着急,大家稍作调整,在线程前面增添.GetAwaiter().GetResult()。那句话是为啥用的啊?是用来取得线程重回值的。

4.IAsyncResult

 

IAsyncResult自.NET1.1起就有了,包括可异步操作的章程的类需求完成它,Task类就完结了该接口

 

 

威尼斯人线上娱乐 42

 

在不借助于Task的景况下怎么落到实处异步呢?

 

class Program

{

    static void Main(string[] args)

    {

        Console.WriteLine(“主程序初始——————–“);

        int threadId;

        AsyncDemo ad = new AsyncDemo();

        AsyncMethodCaller caller = new
AsyncMethodCaller(ad.TestMethod);

 

        IAsyncResult result = caller.BeginInvoke(3000,out threadId,
null, null);

        Thread.Sleep(0);

        Console.WriteLine(“主线程线程 {0}
正在运营.”,Thread.CurrentThread.ManagedThreadId)

        //会阻塞线程,直到后台线程执行达成之后,才会往下实施

        result.AsyncWaitHandle.WaitOne();

        Console.WriteLine(“主程序在做一些业务!!!”);

        //获取异步执行的结果

        string returnValue = caller.EndInvoke(out threadId, result);

        //释放资源

        result.AsyncWaitHandle.Close();

        Console.WriteLine(“主程序结束——————–“);

        Console.Read();

    }

}

public class AsyncDemo

{

    //供后台线程执行的格局

    public string TestMethod(int callDuration, out int threadId)

    {

        Console.WriteLine(“测试方法起头执行.”);

        Thread.Sleep(callDuration);

        threadId = Thread.CurrentThread.ManagedThreadId;

        return String.Format(“测试方法执行的光阴 {0}.”,
callDuration.ToString());

    }

}

public delegate string AsyncMethodCaller(int callDuration, out int
threadId);

 

关键步骤正是水晶绿字体的一部分,运维结果:

 

威尼斯人线上娱乐 43

 

和Task的用法差距不是非常的大!result.AsyncWaitHandle.WaitOne()就象是Task的Wait。

 

5.Parallel

 

最终说一下在循环中开启三十二线程的简单方法:

 

Stopwatch watch1 = new Stopwatch();

watch1.Start();

for (int i = 1; i <= 10; i++)

{

    Console.Write(i + “,”);

    Thread.Sleep(1000);

}

watch1.Stop();

Console.WriteLine(watch1.Elapsed);

Stopwatch watch2 = new Stopwatch();

watch2.Start();

//会调用线程池中的线程

Parallel.For(1, 11, i =>

{

    Console.WriteLine(i + “,线程ID:” +
Thread.CurrentThread.ManagedThreadId);

    Thread.Sleep(1000);

});

watch2.Stop();

Console.WriteLine(watch2.Elapsed);

 

运行结果:

 

威尼斯人线上娱乐 44

 

循环List<T>:

 

List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 6, 7,
8, 9 };

Parallel.ForEach<int>(list, n =>

{

    Console.WriteLine(n);

    Thread.Sleep(1000);

});

 

执行Action[]数组里面包车型客车艺术:

 

Action[]威尼斯人线上娱乐, actions = new Action[] { 

   new Action(()=>{

       Console.WriteLine(“方法1”);

   }),

    new Action(()=>{

       Console.WriteLine(“方法2”);

   })

};

Parallel.Invoke(actions);

这么些逻辑是那样的,假设想要获取线程重返结果,就自然要等待线程甘休。

 

运转一下,大家将看上边包车型地铁结果。

6.异步的回调

 

为了简洁(偷懒),文中全数Task<TResult>的重临值都以向来用task.result获取,那样一旦后台任务没有进行完成的话,主线程会等待其实践完结。那样的话就和协同一样了,一般情形下不会那样用。容易演示一下Task回调函数的接纳:

 

Console.WriteLine(“主线程开头”);

Task<string> task = Task<string>.Run(() => {

    Thread.Sleep(2000); 

    return Thread.CurrentThread.ManagedThreadId.ToString(); 

});

//会等到任务执行完之后执行

task.GetAwaiter().OnCompleted(() =>

{

    Console.WriteLine(task.Result);

});

Console.WriteLine(“主线程甘休”);

Console.Read();

 

推行结果:

 

威尼斯人线上娱乐 45

 

OnCompleted中的代码会在任务执行到位现在执行!

 

此外task.ContinueWith()也是二个重点的不二法门:

 

Console.WriteLine(“主线程发轫”);

Task<string> task = Task<string>.Run(() => {

    Thread.Sleep(2000); 

    return Thread.CurrentThread.ManagedThreadId.ToString(); 

});

task.GetAwaiter().OnCompleted(() =>

{

    Console.WriteLine(task.Result);

});

task.ContinueWith(m=>{Console.WriteLine(“第1个义务实现啦!笔者是第3个职责”);});

Console.WriteLine(“主线程甘休”);

Console.Read();

 

施行结果:

 

威尼斯人线上娱乐 46

 

ContinueWith()方法能够让该后台线程继续执行新的任务。

 

Task的施用只怕相比较灵活的,我们能够切磋下,好了,以上正是全体内容了,篇幅和能力都有数,希望对我们有用!

public static async Task<int> AsyncTest()
        {
            Task.Run(() =>
            {
                Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run1 " + DateTime.Now);
                Thread.Sleep(1000);
            }).GetAwaiter().GetResult();
            return 1;
        }

威尼斯人线上娱乐 47 

只是,好像await
AsyncTest();照旧没启效用。没错,事实就是,他的确不会起效果。。。

那正是说怎么才能让她起效能吧?

率先,大家定义三个平时函数,他的重返值是2个Task,然后我们取得Task后,运维它,再用await等待这么些Task。

于是乎大家就取得这么的结果。

 public static async void Excute()
        {
            Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 开始 Excute " + DateTime.Now);
            var waitTask = AsyncTestRun();
            waitTask.Start();
            int i = await waitTask;
            Console.WriteLine(Thread.CurrentThread.GetHashCode() + " i " + i);
            Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 结束 Excute " + DateTime.Now);
        }
        public static Task<int> AsyncTestRun()
        {
            Task<int> t = new Task<int>(() => {
                Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run1 " + DateTime.Now);
                Thread.Sleep(1000);
                return 100;
            });
            return t;
        }

威尼斯人线上娱乐 48  

如图,那样写await AsyncTest();就起效果了。

从而,照旧这句话,await等待的是线程,不是函数。

但在图里,我们发现很奇怪的有些,截止Excute也是线程3,而不是线程1。也正是说,Await会对线程实行优化。

下边看下两组代码的相比较,让大家就更驾驭的询问下Await。

第3组,使用await等待线程。

public static async void Excute()
{
   Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 开始 Excute " + DateTime.Now);
   await SingleAwait(); 
   Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 结束 Excute " + DateTime.Now);
}

public static async Task SingleAwait()
{
     Console.WriteLine(Thread.CurrentThread.GetHashCode() + " AwaitTest开始 " + DateTime.Now);
     await Task.Run(() =>
            {
                Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run1 " + DateTime.Now);
                Thread.Sleep(1000);
            });
            await Task.Run(() =>
            {
                Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run2 " + DateTime.Now);
                Thread.Sleep(1000);
            });
            Console.WriteLine(Thread.CurrentThread.GetHashCode() + " AwaitTest结束 " + DateTime.Now);
            return;
}

威尼斯人线上娱乐 49

 

其次组,使用等待线程结果,等待线程。

 public static async void Excute()
{
     Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 开始 Excute " + DateTime.Now);
            await SingleNoAwait(); 
     Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 结束 Excute " + DateTime.Now);
        }
public static async Task SingleNoAwait()
{
      Console.WriteLine(Thread.CurrentThread.GetHashCode() + " SingleNoAwait开始 " + DateTime.Now);
       Task.Run(() =>
        {
                Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run1 " + DateTime.Now);
                Thread.Sleep(1000);
            }).GetAwaiter().GetResult();
            Task.Run(() =>
            {
                Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run2 " + DateTime.Now);
                Thread.Sleep(1000);
            }).GetAwaiter().GetResult();
            Console.WriteLine(Thread.CurrentThread.GetHashCode() + " SingleNoAwait结束 " + DateTime.Now);
            return;
}

威尼斯人线上娱乐 50

能够显明的看看,第三组,线程重新回来了主线程第11中学,而首先组,已经被优化到了线程4中。

 

 结语

await是一种很轻便的语法,他着实会让代码简洁一些,但他主动优化线程的效益,即便不打听就动用,或许会招致有个别想不到的BUG发生。

这也是合法为啥只提供了await调用服务的例子,因为,在程序内调用,await依然要了然后,再选择,才平安。

C#语法——委托,架构的血液

C#语法——元组类型

C#语法——泛型的两种利用


注:此小说为原创,欢迎转发,请在作品页面显然地方给出此文链接!
若您认为那篇小说还能够,请点击下右下角的推荐,非凡谢谢!


相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图