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)

 

多线程的意义在于一个应用程序中,有七个实施部分可以同时履行;对于比较耗费时间的操作(例如io,数据库操作),或然等待响应(如WCF通讯)的操作,能够单独开启后台线程来推行,那样主线程就不会阻塞,能够三番7次往下实行;等到后台线程执行达成,再通报主线程,然后做出相应操作!

 

在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("这是后台线程调用");
}

 

实施结果如下图

【金沙注册送58】的这一个事情,await与async的不易打开药格局。 

金沙注册送58 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("这是后台线程调用");
}

 执行结果如下图,

金沙注册送58 2

能够看出在运营后台线程之后,主线程继续往下实行了,并没有等到后台线程执行完之后。

1.1 线程池

 

试想一下,若是有大气的天职急需处理,例如网站后台对于HTTP请求的拍卖,那是否要对每1个呼吁创制多个后台线程呢?鲜明不合适,那会占用多量内部存款和储蓄器,而且往往地开创的经过也会严重影响进程,那怎么做呢?

 

线程池正是为了消除这一标题,把创建的线程存起来,形成八个线程池(里面有多少个线程),当要拍卖职分时,若线程池中有空余线程(前三个任务履行到位后,线程不会被回收,会被安装为空闲状态),则平素调用线程池中的线程执行(例asp.net处理体制中的Application对象),使用事例:

 

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

 

运行结果:

 

金沙注册送58 3

 

能够看来,即便进行了十二回,但并不曾创建拾三个线程。

 

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

 

进行结果如下:

 

金沙注册送58 4

 

金沙注册送58 5

 

能够看到,刚开首唯有四个线程在履行,当一个线程执行实现并释放之后,才会有新的线程来执行措施!

 

除此而外SemaphoreSlim类,仍是能够选拔Semaphore类,感觉越是灵敏,感兴趣的话能够搜一下,那里就不做示范了!

 

 

 正确的打开情势

1.1 线程池

试想一下,借使有多量的天职需求处理,例如网站后台对于HTTP请求的拍卖,那是否要对每种请求创设1个后台线程呢?明显不合适,那会占用多量内部存款和储蓄器,而且往往地开创的进度也会严重影响速度,这如何是好吧?线程池正是为着消除这一题材,把创设的线程存起来,形成二个线程池(里面有多少个线程),当要拍卖职责时,若线程池中有空余线程(前2个任务履行到位后,线程不会被回收,会被设置为空闲状态),则直接调用线程池中的线程执行(例asp.net处理机制中的Application对象),

运用事例:

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

运作结果:

金沙注册送58 6

能够见到,尽管实施了10次,但并从未开创十一个线程。

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("主线程结束");

 

推行结果如下:

 

金沙注册送58 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);
}

 

执行结果:

 

金沙注册送58 8

 

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

 

1.线程(Thread)

 

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

实施结果如下:

金沙注册送58 9金沙注册送58 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("主线程结束");

 

运营结果:

 

金沙注册送58 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("主线程结束");

举行理并了结果如下:

金沙注册送58 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);
}

执行结果:

金沙注册送58 13

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

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成对出现才有含义,看看运维结果:

 

金沙注册送58 14

 

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

 

那正是说是或不是是在蒙受await关键字的时候程序自动开启了贰个后台线程去实践GetString方法吗?

 

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

 

金沙注册送58 15

 

我们能够见见,在遇见await关键字后,没有继续执行GetStrLengthAsync方法前边的操作,也绝非即时反回到main函数中,而是实行了GetString的第三行,以此能够判定await那里并没有打开新的线程去实践GetString方法,而是以共同的法门让GetString方法执行,等到执行到GetString方法中的Task<string>.Run()的时候才由Task开启了后台线程!

 

那么await的机能是何等啊?

 

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

 

那就是说await是怎么完结的吧?有没有打开新线程去等待?

 

金沙注册送58 16

 

只有七个线程(主线程和Task开启的线程)!至于怎么达成的(笔者也不知道……>_<),大家有趣味的话商讨下吧!

 

二十四线程的意思在于1个应用程序中,有多少个实施部分能够同时实施;对于比较耗费时间的操作(例如io,数据库操作),大概等待响应(如WCF通讯)的操作,能够独立开启后台线程来推行,那样主线程就不会阻塞,能够延续往下执行;等到后台线程执行达成,再通报主线程,然后做出相应操作!

① 、await 只幸亏标记了async的函数内选拔。

金沙注册送58 ,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("主线程结束");

运维结果:

金沙注册送58 17

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

不难易行提一下:

Task职务能够透过CancellationTokenSource类来撤废,感觉用得不多,用法相比简单,感兴趣的话能够搜一下!

4.IAsyncResult

 

IAsyncResult自.NET1.1起就有了,包蕴可异步操作的方法的类须要完毕它,Task类就兑现了该接口

 

 

金沙注册送58 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);

 

关键步骤正是新民主主义革命字体的一些,运转结果:

 

金沙注册送58 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);

 

运维结果:

 

金沙注册送58 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成对出现才有含义,

探望运营结果:

金沙注册送58 21

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

那么是还是不是是在遇见await关键字的时候程序自动开启了二个后台线程去执行GetString方法吧?

今昔把GetString方法中的这行注释加上,运营的结果是:

金沙注册送58 22

世家能够看到,在遇见await关键字后,没有继续执行GetStrLengthAsync方法前面包车型地铁操作,也远非及时反回到main函数中,而是进行了GetString的第壹行,以此能够断定await这里并没有打开新的线程去实践GetString方法,而是以联合的章程让GetString方法执行,等到执行到GetString方法中的Task<string>.Run()的时候才由Task开启了后台线程!

那么await的机能是何等啊?

能够从字面上掌握,下面提到task.wait可以让主线程等待后台线程执行实现,await和wait类似,同样是伺机,等待Task<string>.Run()开始的后台线程执行达成,不一致的是await不会阻塞主线程,只会让GetStrLengthAsync方法暂停实施。

那么await是如何是好到的呢?有没有打开新线程去等待?

金沙注册送58 23

唯有多少个线程(主线程和Task开启的线程)!至于怎么形成的(作者也不知道……>_<),大家有趣味的话商讨下啊!

 

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

有没有觉得那是个循环?没错,那便是个巡回。那也便是为啥大家不怎么用他们的原因。那么些轮回很看不惯,那么怎么化解这么些轮回呢?

4.IAsyncResult

IAsyncResult自.NET1.1起就有了,包蕴可异步操作的章程的类须求贯彻它,Task类就兑现了该接口

金沙注册送58 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);

关键步骤正是革命字体的片段,运转结果:

金沙注册送58 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();

 

执行结果:

 

金沙注册送58 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();

 

施行结果:

 

金沙注册送58 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);

运作结果:

金沙注册送58 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();

施行结果:

金沙注册送58 29

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

实施结果:

金沙注册送58 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

金沙注册送58 31

那意味着大家在符合规律调用这五个函数时,他们是一致的。那么用async
Task<int>来修饰int指标是何许啊?

 

目标是为了让这一个情势这么被调用 await
AsyncTest(),但直接那样调用,并不会张开线程,那那样辛劳的梳洗是否就没怎么含义了啊。

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

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

 

大家随后往下看,修改AsyncTest如下。然后,此时再调用await
AsyncTest(),你会神奇的意识,依然没有卵用。。。

1.1 线程池

 

试想一下,借使有恢宏的职分急需处理,例如网站后台对于HTTP请求的处理,那是还是不是要对每二个呼吁创制1个后台线程呢?显著不合适,那会占有多量内部存款和储蓄器,而且一再地开创的进度也会严重影响速度,这如何是好吧?

 

线程池就是为着消除这一题材,把创造的线程存起来,形成一个线程池(里面有几个线程),当要拍卖职分时,若线程池中有空余线程(前叁个职分履行到位后,线程不会被回收,会被设置为空闲状态),则直接调用线程池中的线程执行(例asp.net处理体制中的Application对象),使用事例:

 

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

{

    ThreadPool.QueueUserWorkItem(m =>

    {

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

    });

}

Console.Read();

 

运作结果:

 

金沙注册送58 32

 

可以看来,纵然进行了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();

}

 

施行结果如下:

 

金沙注册送58 33

 

金沙注册送58 34

 

能够阅览,刚开始唯有多个线程在履行,当三个线程执行完毕并释放之后,才会有新的线程来执行措施!

 

除此而外SemaphoreSlim类,还足以使用Semaphore类,感觉尤其灵活,感兴趣的话能够搜一下,那里就不做示范了!

 

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

2.Task

 

Task是.NET4.0投入的,跟线程池ThreadPool的效应看似,用Task开启新任务时,会从线程池中调用线程,而Thread每一趟实例化都会创制1个新的线程。

 

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(“主线程结束”);

 

履行结果如下:

 

金沙注册送58 35

 

敞开新职务的艺术:Task.Run()可能Task.Factory.StartNew(),开启的是后台线程要在主线程中等待后台线程执行实现,能够行使Wait方法(会以3头的方法来进行)。不用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);

}

 

执行结果:

 

金沙注册送58 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(“主线程结束”);

 

运营结果:

 

金沙注册送58 37

 

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

 

简单易行提一下:

 

Task职分能够透过CancellationTokenSource类来废除,感觉用得不多,用法比较不难,感兴趣的话能够搜一下!

 

金沙注册送58 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成对出现才有意义,看看运转结果:

 

金沙注册送58 39

 

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

 

那就是说是或不是是在蒙受await关键字的时候程序自动开启了1个后台线程去执行GetString方法吗?

 

今后把GetString方法中的那行注释加上,运行的结果是:

 

金沙注册送58 40

 

世家能够看来,在遇见await关键字后,没有继续执行GetStrLengthAsync方法前面包车型地铁操作,也从没应声反回到main函数中,而是实行了GetString的首先行,以此能够断定await那里并从未开启新的线程去实践GetString方法,而是以共同的主意让GetString方法执行,等到执行到GetString方法中的Task<string>.Run()的时候才由Task开启了后台线程!

 

那么await的功能是如何吗?

 

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

 

那么await是如何做到的啊?有没有打开新线程去等待?

 

金沙注册送58 41

 

唯有五个线程(主线程和Task开启的线程)!至于如何是好到的(笔者也不知道……>_<),我们有趣味的话研究下呢!

 

别着急,大家稍作调整,在线程前面增添.GetAwaiter().GetResult()。那句话是干什么用的呢?是用来取得线程重返值的。

4.IAsyncResult

 

IAsyncResult自.NET1.1起就有了,包罗可异步操作的办法的类要求贯彻它,Task类就落到实处了该接口

 

 

金沙注册送58 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);

 

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

 

金沙注册送58 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);

 

运维结果:

 

金沙注册送58 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();

 

履行结果:

 

金沙注册送58 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(“第三个职责完结啦!笔者是第三个义务”);});

Console.WriteLine(“主线程截至”);

Console.Read();

 

进行结果:

 

金沙注册送58 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;
        }

金沙注册送58 47 

只是,好像await
AsyncTest();依旧没启功效。没错,事实便是,他确实不会起功能。。。

那就是说怎么才能让他起效果吧?

首先,大家定义二个经常函数,他的再次回到值是二个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;
        }

金沙注册送58 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;
}

金沙注册送58 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;
}

金沙注册送58 50

能够一目精通的看出,第2组,线程重新重回了主线程第11中学,而首先组,已经被优化到了线程4中。

 

 结语

await是一种很便利的语法,他实在会让代码简洁一些,但她主动优化线程的意义,假诺不打听就利用,大概会促成有的奇怪的BUG发生。

那也是法定为什么只提供了await调用劳动的例证,因为,在程序内调用,await照旧要打听后,再使用,才安然。

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

C#语法——元组类型

C#语法——泛型的有余应用


注:此文章为原创,欢迎转载,请在小说页面显然地点给出此文链接!
若您觉得那篇作品还不易,请点击下右下角的推荐,格外感激!

相关文章

网站地图xml地图