await与async的正确打开药方式,的这个事儿

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)

 

二十多线程的意思在于3个应用程序中,有多少个实施部分能够而且履行;对于相比耗时的操作(例如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个后台线程呢?分明不合适,那会占有大批量内部存款和储蓄器,而且多次地创设的进度也会严重影响进程,那如何做吧?

 

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

 

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

 

运转结果:

 

亚洲必赢官网 3

 

能够看来,就算实施了拾贰回,但并不曾创制11个线程。

 

1.2 信号量(Semaphore)

 

Semaphore负责协调线程,能够界定对某一能源访问的线程数量,这里对塞马phoreSlim类的用法做三个简短的例子:

 

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类,还能够运用Semaphore类,感觉越来越灵敏,感兴趣的话能够搜一下,那里就不做示范了!

 

 

 正确的打开药格局

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

能够看看,即便实施了拾1次,但并没有创制十个线程。

2.Task

 

Task是.NET4.0出席的,跟线程池ThreadPool的效率看似,用Task开启新职务时,会从线程池中调用线程,而Thread每一次实例化都会创制3个新的线程。

 

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会开启6个线程,用Task(用了线程池)开启了2个!

 

1.线程(Thread)

 

 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();
}

实践结果如下:

亚洲必赢官网 9亚洲必赢官网 10

能够看出,刚开端唯有三个线程在进行,当2个线程执行完结并释放之后,才会有新的线程来施行情势!

除去塞马phoreSlim类,还是能够利用塞马phore类,感觉更是灵敏,感兴趣的话能够搜一下,那里就不做示范了!

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每一遍实例化都会创立二个新的线程。

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会开启八个线程,用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关键字的时候程序自动开启了3个后台线程去执行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的正确打开药方式,的这个事儿。二 、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回调函数的运用:

 

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()也是一个重庆大学的不二法门:

 

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

 

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

 

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()也是3个重大的艺术:

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

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

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请求的拍卖,那是否要对种种呼吁成立二个后台线程呢?显明不合适,那会占用大量内部存款和储蓄器,而且往往地创立的进程也会严重影响进程,那如何是好呢?

 

线程池便是为了缓解这一难点,把创设的线程存起来,形成三个线程池(里面有八个线程),当要处理职责时,若线程池中有空闲线程(前一个任务履行到位后,线程不会被回收,会被安装为空闲状态),则直接调用线程池中的线程执行(例asp.net处理机制中的Application对象),使用事例:

 

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

{

    ThreadPool.QueueUserWorkItem(m =>

    {

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

    });

}

Console.Read();

 

运营结果:

 

亚洲必赢官网 32

 

能够看出,即便实施了11次,但并不曾创建10个线程。

 

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();

}

 

实行理并了结果如下:

 

亚洲必赢官网 33

 

亚洲必赢官网 34

 

能够看看,刚开始只有多个线程在履行,当三个线程执行完结并释放之后,才会有新的线程来实施办法!

 

除了这一个之外SemaphoreSlim类,还足以选取Semaphore类,感觉特别灵活,感兴趣的话能够搜一下,那里就不做示范了!

 

Excute方法平常执行,而AsyncTest内运维的线程,自个儿实施本人的。

2.Task

 

Task是.NET4.0加盟的,跟线程池ThreadPool的功能相近,用Task开启新义务时,会从线程池中调用线程,而Thread每一趟实例化都会成立五个新的线程。

 

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

//Task.Run运维3个线程

//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会开启多少个线程,用Task(用了线程池)开启了三个!

 

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.孔蒂nueWith()也是三个重中之重的形式:

 

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();

 

施行结果:

 

亚洲必赢官网 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。

首先组,使用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地图